blob: 047ee644aa91df1435cc2ad9e043e108243a1d0b [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Andrew Vasquezfa90c542005-10-27 11:10:08 -07002 * QLogic Fibre Channel HBA Driver
Andrew Vasquez01e58d82008-04-03 13:13:13 -07003 * Copyright (c) 2003-2008 QLogic Corporation
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 *
Andrew Vasquezfa90c542005-10-27 11:10:08 -07005 * See LICENSE.qla2xxx for copyright and licensing details.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006 */
7#include "qla_def.h"
8
9#include <linux/moduleparam.h>
10#include <linux/vmalloc.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070011#include <linux/delay.h>
Christoph Hellwig39a11242006-02-14 18:46:22 +010012#include <linux/kthread.h>
Daniel Walkere1e82b62008-05-12 22:21:10 -070013#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070014
15#include <scsi/scsi_tcq.h>
16#include <scsi/scsicam.h>
17#include <scsi/scsi_transport.h>
18#include <scsi/scsi_transport_fc.h>
19
20/*
21 * Driver version
22 */
23char qla2x00_version_str[40];
24
25/*
26 * SRB allocation cache
27 */
Christoph Lametere18b8902006-12-06 20:33:20 -080028static struct kmem_cache *srb_cachep;
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
Seokmann Ju2c3dfe32007-07-05 13:16:51 -070030int num_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -070031int ql2xlogintimeout = 20;
32module_param(ql2xlogintimeout, int, S_IRUGO|S_IRUSR);
33MODULE_PARM_DESC(ql2xlogintimeout,
34 "Login timeout value in seconds.");
35
Andrew Vasqueza7b61842007-05-07 07:42:59 -070036int qlport_down_retry;
Linus Torvalds1da177e2005-04-16 15:20:36 -070037module_param(qlport_down_retry, int, S_IRUGO|S_IRUSR);
38MODULE_PARM_DESC(qlport_down_retry,
Jesper Juhl900d9f92006-06-30 02:33:07 -070039 "Maximum number of command retries to a port that returns "
Linus Torvalds1da177e2005-04-16 15:20:36 -070040 "a PORT-DOWN status.");
41
Linus Torvalds1da177e2005-04-16 15:20:36 -070042int ql2xplogiabsentdevice;
43module_param(ql2xplogiabsentdevice, int, S_IRUGO|S_IWUSR);
44MODULE_PARM_DESC(ql2xplogiabsentdevice,
45 "Option to enable PLOGI to devices that are not present after "
Jesper Juhl900d9f92006-06-30 02:33:07 -070046 "a Fabric scan. This is needed for several broken switches. "
Linus Torvalds1da177e2005-04-16 15:20:36 -070047 "Default is 0 - no PLOGI. 1 - perfom PLOGI.");
48
Linus Torvalds1da177e2005-04-16 15:20:36 -070049int ql2xloginretrycount = 0;
50module_param(ql2xloginretrycount, int, S_IRUGO|S_IRUSR);
51MODULE_PARM_DESC(ql2xloginretrycount,
52 "Specify an alternate value for the NVRAM login retry count.");
53
Andrew Vasqueza7a167b2006-06-23 16:10:29 -070054int ql2xallocfwdump = 1;
55module_param(ql2xallocfwdump, int, S_IRUGO|S_IRUSR);
56MODULE_PARM_DESC(ql2xallocfwdump,
57 "Option to enable allocation of memory for a firmware dump "
58 "during HBA initialization. Memory allocation requirements "
59 "vary by ISP type. Default is 1 - allocate memory.");
60
Andrew Vasquez11010fe2006-10-06 09:54:59 -070061int ql2xextended_error_logging;
Andrew Vasquez27d94032007-03-12 10:41:30 -070062module_param(ql2xextended_error_logging, int, S_IRUGO|S_IWUSR);
Andrew Vasquez11010fe2006-10-06 09:54:59 -070063MODULE_PARM_DESC(ql2xextended_error_logging,
Andrew Vasquez01819442006-06-23 16:11:10 -070064 "Option to enable extended error logging, "
65 "Default is 0 - no logging. 1 - log errors.");
66
Linus Torvalds1da177e2005-04-16 15:20:36 -070067static void qla2x00_free_device(scsi_qla_host_t *);
68
69static void qla2x00_config_dma_addressing(scsi_qla_host_t *ha);
70
Andrew Vasquez7e47e5c2008-04-24 15:21:26 -070071int ql2xfdmienable=1;
Andrew Vasquezcca53352005-08-26 19:08:30 -070072module_param(ql2xfdmienable, int, S_IRUGO|S_IRUSR);
73MODULE_PARM_DESC(ql2xfdmienable,
74 "Enables FDMI registratons "
75 "Default is 0 - no FDMI. 1 - perfom FDMI.");
76
Andrew Vasquezdf7baa52006-10-13 09:33:39 -070077#define MAX_Q_DEPTH 32
78static int ql2xmaxqdepth = MAX_Q_DEPTH;
79module_param(ql2xmaxqdepth, int, S_IRUGO|S_IWUSR);
80MODULE_PARM_DESC(ql2xmaxqdepth,
81 "Maximum queue depth to report for target devices.");
82
83int ql2xqfullrampup = 120;
84module_param(ql2xqfullrampup, int, S_IRUGO|S_IWUSR);
85MODULE_PARM_DESC(ql2xqfullrampup,
86 "Number of seconds to wait to begin to ramp-up the queue "
87 "depth for a device after a queue-full condition has been "
88 "detected. Default is 120 seconds.");
89
Linus Torvalds1da177e2005-04-16 15:20:36 -070090/*
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -070091 * SCSI host template entry points
Linus Torvalds1da177e2005-04-16 15:20:36 -070092 */
93static int qla2xxx_slave_configure(struct scsi_device * device);
f4f051e2005-04-17 15:02:26 -050094static int qla2xxx_slave_alloc(struct scsi_device *);
Andrew Vasquez1e99e332006-11-22 08:24:48 -080095static int qla2xxx_scan_finished(struct Scsi_Host *, unsigned long time);
96static void qla2xxx_scan_start(struct Scsi_Host *);
f4f051e2005-04-17 15:02:26 -050097static void qla2xxx_slave_destroy(struct scsi_device *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070098static int qla2x00_queuecommand(struct scsi_cmnd *cmd,
99 void (*fn)(struct scsi_cmnd *));
Andrew Vasquezfca29702005-07-06 10:31:47 -0700100static int qla24xx_queuecommand(struct scsi_cmnd *cmd,
101 void (*fn)(struct scsi_cmnd *));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102static int qla2xxx_eh_abort(struct scsi_cmnd *);
103static int qla2xxx_eh_device_reset(struct scsi_cmnd *);
Andrew Vasquez523ec772008-04-03 13:13:24 -0700104static int qla2xxx_eh_target_reset(struct scsi_cmnd *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105static int qla2xxx_eh_bus_reset(struct scsi_cmnd *);
106static int qla2xxx_eh_host_reset(struct scsi_cmnd *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107
Andrew Vasquezce7e4af2005-08-26 19:09:30 -0700108static int qla2x00_change_queue_depth(struct scsi_device *, int);
109static int qla2x00_change_queue_type(struct scsi_device *, int);
110
Adrian Bunka824ebb2008-01-17 09:02:15 -0800111static struct scsi_host_template qla2x00_driver_template = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 .module = THIS_MODULE,
Andrew Vasquezcb630672006-05-17 15:09:45 -0700113 .name = QLA2XXX_DRIVER_NAME,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114 .queuecommand = qla2x00_queuecommand,
115
116 .eh_abort_handler = qla2xxx_eh_abort,
117 .eh_device_reset_handler = qla2xxx_eh_device_reset,
Andrew Vasquez523ec772008-04-03 13:13:24 -0700118 .eh_target_reset_handler = qla2xxx_eh_target_reset,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119 .eh_bus_reset_handler = qla2xxx_eh_bus_reset,
120 .eh_host_reset_handler = qla2xxx_eh_host_reset,
121
122 .slave_configure = qla2xxx_slave_configure,
123
f4f051e2005-04-17 15:02:26 -0500124 .slave_alloc = qla2xxx_slave_alloc,
125 .slave_destroy = qla2xxx_slave_destroy,
Andrew Vasquez1e99e332006-11-22 08:24:48 -0800126 .scan_finished = qla2xxx_scan_finished,
127 .scan_start = qla2xxx_scan_start,
Andrew Vasquezce7e4af2005-08-26 19:09:30 -0700128 .change_queue_depth = qla2x00_change_queue_depth,
129 .change_queue_type = qla2x00_change_queue_type,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 .this_id = -1,
131 .cmd_per_lun = 3,
132 .use_clustering = ENABLE_CLUSTERING,
133 .sg_tablesize = SG_ALL,
134
135 /*
136 * The RISC allows for each command to transfer (2^32-1) bytes of data,
137 * which equates to 0x800000 sectors.
138 */
139 .max_sectors = 0xFFFF,
Andrew Vasquezafb046e2005-08-26 19:09:40 -0700140 .shost_attrs = qla2x00_host_attrs,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141};
142
Seokmann Ju2c3dfe32007-07-05 13:16:51 -0700143struct scsi_host_template qla24xx_driver_template = {
Andrew Vasquezfca29702005-07-06 10:31:47 -0700144 .module = THIS_MODULE,
Andrew Vasquezcb630672006-05-17 15:09:45 -0700145 .name = QLA2XXX_DRIVER_NAME,
Andrew Vasquezfca29702005-07-06 10:31:47 -0700146 .queuecommand = qla24xx_queuecommand,
147
148 .eh_abort_handler = qla2xxx_eh_abort,
149 .eh_device_reset_handler = qla2xxx_eh_device_reset,
Andrew Vasquez523ec772008-04-03 13:13:24 -0700150 .eh_target_reset_handler = qla2xxx_eh_target_reset,
Andrew Vasquezfca29702005-07-06 10:31:47 -0700151 .eh_bus_reset_handler = qla2xxx_eh_bus_reset,
152 .eh_host_reset_handler = qla2xxx_eh_host_reset,
153
154 .slave_configure = qla2xxx_slave_configure,
155
156 .slave_alloc = qla2xxx_slave_alloc,
157 .slave_destroy = qla2xxx_slave_destroy,
Andrew Vasquezed677082007-03-12 10:41:27 -0700158 .scan_finished = qla2xxx_scan_finished,
159 .scan_start = qla2xxx_scan_start,
Andrew Vasquezce7e4af2005-08-26 19:09:30 -0700160 .change_queue_depth = qla2x00_change_queue_depth,
161 .change_queue_type = qla2x00_change_queue_type,
Andrew Vasquezfca29702005-07-06 10:31:47 -0700162 .this_id = -1,
163 .cmd_per_lun = 3,
164 .use_clustering = ENABLE_CLUSTERING,
165 .sg_tablesize = SG_ALL,
166
167 .max_sectors = 0xFFFF,
Andrew Vasquezafb046e2005-08-26 19:09:40 -0700168 .shost_attrs = qla2x00_host_attrs,
Andrew Vasquezfca29702005-07-06 10:31:47 -0700169};
170
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171static struct scsi_transport_template *qla2xxx_transport_template = NULL;
Seokmann Ju2c3dfe32007-07-05 13:16:51 -0700172struct scsi_transport_template *qla2xxx_transport_vport_template = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174/* TODO Convert to inlines
175 *
176 * Timer routines
177 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178
Seokmann Ju2c3dfe32007-07-05 13:16:51 -0700179__inline__ void
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180qla2x00_start_timer(scsi_qla_host_t *ha, void *func, unsigned long interval)
181{
182 init_timer(&ha->timer);
183 ha->timer.expires = jiffies + interval * HZ;
184 ha->timer.data = (unsigned long)ha;
185 ha->timer.function = (void (*)(unsigned long))func;
186 add_timer(&ha->timer);
187 ha->timer_active = 1;
188}
189
190static inline void
191qla2x00_restart_timer(scsi_qla_host_t *ha, unsigned long interval)
192{
193 mod_timer(&ha->timer, jiffies + interval * HZ);
194}
195
Adrian Bunka824ebb2008-01-17 09:02:15 -0800196static __inline__ void
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197qla2x00_stop_timer(scsi_qla_host_t *ha)
198{
199 del_timer_sync(&ha->timer);
200 ha->timer_active = 0;
201}
202
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203static int qla2x00_do_dpc(void *data);
204
205static void qla2x00_rst_aen(scsi_qla_host_t *);
206
Andrew Vasqueze8711082008-01-31 12:33:48 -0800207static int qla2x00_mem_alloc(scsi_qla_host_t *);
Adrian Bunka824ebb2008-01-17 09:02:15 -0800208static void qla2x00_mem_free(scsi_qla_host_t *ha);
f4f051e2005-04-17 15:02:26 -0500209static void qla2x00_sp_free_dma(scsi_qla_host_t *, srb_t *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211/* -------------------------------------------------------------------------- */
212
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213static char *
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700214qla2x00_pci_info_str(struct scsi_qla_host *ha, char *str)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215{
216 static char *pci_bus_modes[] = {
217 "33", "66", "100", "133",
218 };
219 uint16_t pci_bus;
220
221 strcpy(str, "PCI");
222 pci_bus = (ha->pci_attr & (BIT_9 | BIT_10)) >> 9;
223 if (pci_bus) {
224 strcat(str, "-X (");
225 strcat(str, pci_bus_modes[pci_bus]);
226 } else {
227 pci_bus = (ha->pci_attr & BIT_8) >> 8;
228 strcat(str, " (");
229 strcat(str, pci_bus_modes[pci_bus]);
230 }
231 strcat(str, " MHz)");
232
233 return (str);
234}
235
Andrew Vasquezfca29702005-07-06 10:31:47 -0700236static char *
237qla24xx_pci_info_str(struct scsi_qla_host *ha, char *str)
238{
239 static char *pci_bus_modes[] = { "33", "66", "100", "133", };
240 uint32_t pci_bus;
241 int pcie_reg;
242
243 pcie_reg = pci_find_capability(ha->pdev, PCI_CAP_ID_EXP);
244 if (pcie_reg) {
245 char lwstr[6];
246 uint16_t pcie_lstat, lspeed, lwidth;
247
248 pcie_reg += 0x12;
249 pci_read_config_word(ha->pdev, pcie_reg, &pcie_lstat);
250 lspeed = pcie_lstat & (BIT_0 | BIT_1 | BIT_2 | BIT_3);
251 lwidth = (pcie_lstat &
252 (BIT_4 | BIT_5 | BIT_6 | BIT_7 | BIT_8 | BIT_9)) >> 4;
253
254 strcpy(str, "PCIe (");
255 if (lspeed == 1)
Andrew Vasquezc87a0d82008-04-03 13:13:21 -0700256 strcat(str, "2.5GT/s ");
Andrew Vasquezc3a2f0d2007-07-19 20:37:34 -0700257 else if (lspeed == 2)
Andrew Vasquezc87a0d82008-04-03 13:13:21 -0700258 strcat(str, "5.0GT/s ");
Andrew Vasquezfca29702005-07-06 10:31:47 -0700259 else
260 strcat(str, "<unknown> ");
261 snprintf(lwstr, sizeof(lwstr), "x%d)", lwidth);
262 strcat(str, lwstr);
263
264 return str;
265 }
266
267 strcpy(str, "PCI");
268 pci_bus = (ha->pci_attr & CSRX_PCIX_BUS_MODE_MASK) >> 8;
269 if (pci_bus == 0 || pci_bus == 8) {
270 strcat(str, " (");
271 strcat(str, pci_bus_modes[pci_bus >> 3]);
272 } else {
273 strcat(str, "-X ");
274 if (pci_bus & BIT_2)
275 strcat(str, "Mode 2");
276 else
277 strcat(str, "Mode 1");
278 strcat(str, " (");
279 strcat(str, pci_bus_modes[pci_bus & ~BIT_2]);
280 }
281 strcat(str, " MHz)");
282
283 return str;
284}
285
Adrian Bunke5f82ab2006-11-08 19:55:50 -0800286static char *
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700287qla2x00_fw_version_str(struct scsi_qla_host *ha, char *str)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288{
289 char un_str[10];
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -0700290
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 sprintf(str, "%d.%02d.%02d ", ha->fw_major_version,
292 ha->fw_minor_version,
293 ha->fw_subminor_version);
294
295 if (ha->fw_attributes & BIT_9) {
296 strcat(str, "FLX");
297 return (str);
298 }
299
300 switch (ha->fw_attributes & 0xFF) {
301 case 0x7:
302 strcat(str, "EF");
303 break;
304 case 0x17:
305 strcat(str, "TP");
306 break;
307 case 0x37:
308 strcat(str, "IP");
309 break;
310 case 0x77:
311 strcat(str, "VI");
312 break;
313 default:
314 sprintf(un_str, "(%x)", ha->fw_attributes);
315 strcat(str, un_str);
316 break;
317 }
318 if (ha->fw_attributes & 0x100)
319 strcat(str, "X");
320
321 return (str);
322}
323
Adrian Bunke5f82ab2006-11-08 19:55:50 -0800324static char *
Andrew Vasquezfca29702005-07-06 10:31:47 -0700325qla24xx_fw_version_str(struct scsi_qla_host *ha, char *str)
326{
Andrew Vasquezf0883ac2005-07-08 17:58:43 -0700327 sprintf(str, "%d.%02d.%02d ", ha->fw_major_version,
328 ha->fw_minor_version,
329 ha->fw_subminor_version);
330
Andrew Vasquezfca29702005-07-06 10:31:47 -0700331 if (ha->fw_attributes & BIT_0)
332 strcat(str, "[Class 2] ");
333 if (ha->fw_attributes & BIT_1)
334 strcat(str, "[IP] ");
335 if (ha->fw_attributes & BIT_2)
336 strcat(str, "[Multi-ID] ");
Andrew Vasquezc3a2f0d2007-07-19 20:37:34 -0700337 if (ha->fw_attributes & BIT_3)
338 strcat(str, "[SB-2] ");
339 if (ha->fw_attributes & BIT_4)
340 strcat(str, "[T10 CRC] ");
341 if (ha->fw_attributes & BIT_5)
342 strcat(str, "[VI] ");
Harihara Kadayam4d4df192008-04-03 13:13:26 -0700343 if (ha->fw_attributes & BIT_10)
344 strcat(str, "[84XX] ");
Andrew Vasquezfca29702005-07-06 10:31:47 -0700345 if (ha->fw_attributes & BIT_13)
346 strcat(str, "[Experimental]");
347 return str;
Andrew Vasquezfca29702005-07-06 10:31:47 -0700348}
349
350static inline srb_t *
351qla2x00_get_new_sp(scsi_qla_host_t *ha, fc_port_t *fcport,
352 struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
353{
354 srb_t *sp;
355
356 sp = mempool_alloc(ha->srb_mempool, GFP_ATOMIC);
357 if (!sp)
358 return sp;
359
Andrew Vasquezfca29702005-07-06 10:31:47 -0700360 sp->ha = ha;
361 sp->fcport = fcport;
362 sp->cmd = cmd;
363 sp->flags = 0;
364 CMD_SP(cmd) = (void *)sp;
365 cmd->scsi_done = done;
366
367 return sp;
368}
369
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370static int
f4f051e2005-04-17 15:02:26 -0500371qla2x00_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372{
Andrew Vasquezf363b942007-09-20 14:07:45 -0700373 scsi_qla_host_t *ha = shost_priv(cmd->device->host);
bdf79622005-04-17 15:06:53 -0500374 fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
James.Smart@Emulex.Com19a7b4a2005-10-18 12:03:35 -0400375 struct fc_rport *rport = starget_to_rport(scsi_target(cmd->device));
f4f051e2005-04-17 15:02:26 -0500376 srb_t *sp;
377 int rval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378
Seokmann Ju14e660e2007-09-20 14:07:36 -0700379 if (unlikely(pci_channel_offline(ha->pdev))) {
380 cmd->result = DID_REQUEUE << 16;
381 goto qc_fail_command;
382 }
383
James.Smart@Emulex.Com19a7b4a2005-10-18 12:03:35 -0400384 rval = fc_remote_port_chkready(rport);
385 if (rval) {
386 cmd->result = rval;
f4f051e2005-04-17 15:02:26 -0500387 goto qc_fail_command;
388 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389
andrew.vasquez@qlogic.com387f96b2006-02-07 08:45:45 -0800390 /* Close window on fcport/rport state-transitioning. */
Seokmann Ju5f3a9a22008-07-10 16:55:47 -0700391 if (fcport->drport) {
andrew.vasquez@qlogic.com387f96b2006-02-07 08:45:45 -0800392 cmd->result = DID_IMM_RETRY << 16;
393 goto qc_fail_command;
394 }
395
f4f051e2005-04-17 15:02:26 -0500396 if (atomic_read(&fcport->state) != FCS_ONLINE) {
397 if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD ||
398 atomic_read(&ha->loop_state) == LOOP_DEAD) {
399 cmd->result = DID_NO_CONNECT << 16;
400 goto qc_fail_command;
401 }
402 goto qc_host_busy;
403 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404
405 spin_unlock_irq(ha->host->host_lock);
406
Andrew Vasquezfca29702005-07-06 10:31:47 -0700407 sp = qla2x00_get_new_sp(ha, fcport, cmd, done);
408 if (!sp)
f4f051e2005-04-17 15:02:26 -0500409 goto qc_host_busy_lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410
f4f051e2005-04-17 15:02:26 -0500411 rval = qla2x00_start_scsi(sp);
412 if (rval != QLA_SUCCESS)
413 goto qc_host_busy_free_sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 spin_lock_irq(ha->host->host_lock);
416
f4f051e2005-04-17 15:02:26 -0500417 return 0;
418
419qc_host_busy_free_sp:
420 qla2x00_sp_free_dma(ha, sp);
f4f051e2005-04-17 15:02:26 -0500421 mempool_free(sp, ha->srb_mempool);
422
423qc_host_busy_lock:
424 spin_lock_irq(ha->host->host_lock);
425
426qc_host_busy:
427 return SCSI_MLQUEUE_HOST_BUSY;
428
429qc_fail_command:
430 done(cmd);
431
432 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433}
434
Andrew Vasquezfca29702005-07-06 10:31:47 -0700435
436static int
437qla24xx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
438{
Andrew Vasquezf363b942007-09-20 14:07:45 -0700439 scsi_qla_host_t *ha = shost_priv(cmd->device->host);
Andrew Vasquezfca29702005-07-06 10:31:47 -0700440 fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
James.Smart@Emulex.Com19a7b4a2005-10-18 12:03:35 -0400441 struct fc_rport *rport = starget_to_rport(scsi_target(cmd->device));
Andrew Vasquezfca29702005-07-06 10:31:47 -0700442 srb_t *sp;
443 int rval;
Seokmann Ju2c3dfe32007-07-05 13:16:51 -0700444 scsi_qla_host_t *pha = to_qla_parent(ha);
Andrew Vasquezfca29702005-07-06 10:31:47 -0700445
Seokmann Ju14e660e2007-09-20 14:07:36 -0700446 if (unlikely(pci_channel_offline(ha->pdev))) {
447 cmd->result = DID_REQUEUE << 16;
448 goto qc24_fail_command;
449 }
450
James.Smart@Emulex.Com19a7b4a2005-10-18 12:03:35 -0400451 rval = fc_remote_port_chkready(rport);
452 if (rval) {
453 cmd->result = rval;
Andrew Vasquezfca29702005-07-06 10:31:47 -0700454 goto qc24_fail_command;
455 }
456
andrew.vasquez@qlogic.com387f96b2006-02-07 08:45:45 -0800457 /* Close window on fcport/rport state-transitioning. */
Seokmann Ju5f3a9a22008-07-10 16:55:47 -0700458 if (fcport->drport) {
andrew.vasquez@qlogic.com387f96b2006-02-07 08:45:45 -0800459 cmd->result = DID_IMM_RETRY << 16;
460 goto qc24_fail_command;
461 }
462
Andrew Vasquezfca29702005-07-06 10:31:47 -0700463 if (atomic_read(&fcport->state) != FCS_ONLINE) {
464 if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD ||
Seokmann Ju2c3dfe32007-07-05 13:16:51 -0700465 atomic_read(&pha->loop_state) == LOOP_DEAD) {
Andrew Vasquezfca29702005-07-06 10:31:47 -0700466 cmd->result = DID_NO_CONNECT << 16;
467 goto qc24_fail_command;
468 }
469 goto qc24_host_busy;
470 }
471
472 spin_unlock_irq(ha->host->host_lock);
473
Seokmann Ju2c3dfe32007-07-05 13:16:51 -0700474 sp = qla2x00_get_new_sp(pha, fcport, cmd, done);
Andrew Vasquezfca29702005-07-06 10:31:47 -0700475 if (!sp)
476 goto qc24_host_busy_lock;
477
478 rval = qla24xx_start_scsi(sp);
479 if (rval != QLA_SUCCESS)
480 goto qc24_host_busy_free_sp;
481
482 spin_lock_irq(ha->host->host_lock);
483
484 return 0;
485
486qc24_host_busy_free_sp:
Seokmann Ju2c3dfe32007-07-05 13:16:51 -0700487 qla2x00_sp_free_dma(pha, sp);
488 mempool_free(sp, pha->srb_mempool);
Andrew Vasquezfca29702005-07-06 10:31:47 -0700489
490qc24_host_busy_lock:
491 spin_lock_irq(ha->host->host_lock);
492
493qc24_host_busy:
494 return SCSI_MLQUEUE_HOST_BUSY;
495
496qc24_fail_command:
497 done(cmd);
498
499 return 0;
500}
501
502
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503/*
504 * qla2x00_eh_wait_on_command
505 * Waits for the command to be returned by the Firmware for some
506 * max time.
507 *
508 * Input:
509 * ha = actual ha whose done queue will contain the command
510 * returned by firmware.
511 * cmd = Scsi Command to wait on.
512 * flag = Abort/Reset(Bus or Device Reset)
513 *
514 * Return:
515 * Not Found : 0
516 * Found : 1
517 */
518static int
519qla2x00_eh_wait_on_command(scsi_qla_host_t *ha, struct scsi_cmnd *cmd)
520{
Andrew Vasquezfe74c712005-08-26 19:10:10 -0700521#define ABORT_POLLING_PERIOD 1000
522#define ABORT_WAIT_ITER ((10 * 1000) / (ABORT_POLLING_PERIOD))
f4f051e2005-04-17 15:02:26 -0500523 unsigned long wait_iter = ABORT_WAIT_ITER;
524 int ret = QLA_SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525
f4f051e2005-04-17 15:02:26 -0500526 while (CMD_SP(cmd)) {
Andrew Vasquezfe74c712005-08-26 19:10:10 -0700527 msleep(ABORT_POLLING_PERIOD);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528
f4f051e2005-04-17 15:02:26 -0500529 if (--wait_iter)
530 break;
531 }
532 if (CMD_SP(cmd))
533 ret = QLA_FUNCTION_FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534
f4f051e2005-04-17 15:02:26 -0500535 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536}
537
538/*
539 * qla2x00_wait_for_hba_online
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -0700540 * Wait till the HBA is online after going through
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 * <= MAX_RETRIES_OF_ISP_ABORT or
542 * finally HBA is disabled ie marked offline
543 *
544 * Input:
545 * ha - pointer to host adapter structure
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -0700546 *
547 * Note:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 * Does context switching-Release SPIN_LOCK
549 * (if any) before calling this routine.
550 *
551 * Return:
552 * Success (Adapter is online) : 0
553 * Failed (Adapter is offline/disabled) : 1
554 */
andrew.vasquez@qlogic.com854165f2006-01-31 16:05:17 -0800555int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556qla2x00_wait_for_hba_online(scsi_qla_host_t *ha)
557{
Andrew Vasquezfca29702005-07-06 10:31:47 -0700558 int return_status;
559 unsigned long wait_online;
Seokmann Ju2c3dfe32007-07-05 13:16:51 -0700560 scsi_qla_host_t *pha = to_qla_parent(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -0700562 wait_online = jiffies + (MAX_LOOP_TIMEOUT * HZ);
Seokmann Ju2c3dfe32007-07-05 13:16:51 -0700563 while (((test_bit(ISP_ABORT_NEEDED, &pha->dpc_flags)) ||
564 test_bit(ABORT_ISP_ACTIVE, &pha->dpc_flags) ||
565 test_bit(ISP_ABORT_RETRY, &pha->dpc_flags) ||
566 pha->dpc_active) && time_before(jiffies, wait_online)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567
568 msleep(1000);
569 }
Seokmann Ju2c3dfe32007-07-05 13:16:51 -0700570 if (pha->flags.online)
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -0700571 return_status = QLA_SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 else
573 return_status = QLA_FUNCTION_FAILED;
574
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 return (return_status);
576}
577
578/*
579 * qla2x00_wait_for_loop_ready
580 * Wait for MAX_LOOP_TIMEOUT(5 min) value for loop
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -0700581 * to be in LOOP_READY state.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 * Input:
583 * ha - pointer to host adapter structure
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -0700584 *
585 * Note:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 * Does context switching-Release SPIN_LOCK
587 * (if any) before calling this routine.
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -0700588 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 *
590 * Return:
591 * Success (LOOP_READY) : 0
592 * Failed (LOOP_NOT_READY) : 1
593 */
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -0700594static inline int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595qla2x00_wait_for_loop_ready(scsi_qla_host_t *ha)
596{
597 int return_status = QLA_SUCCESS;
598 unsigned long loop_timeout ;
Seokmann Ju2c3dfe32007-07-05 13:16:51 -0700599 scsi_qla_host_t *pha = to_qla_parent(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600
601 /* wait for 5 min at the max for loop to be ready */
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -0700602 loop_timeout = jiffies + (MAX_LOOP_TIMEOUT * HZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603
Seokmann Ju2c3dfe32007-07-05 13:16:51 -0700604 while ((!atomic_read(&pha->loop_down_timer) &&
605 atomic_read(&pha->loop_state) == LOOP_DOWN) ||
606 atomic_read(&pha->loop_state) != LOOP_READY) {
607 if (atomic_read(&pha->loop_state) == LOOP_DEAD) {
Ravi Anand57680082006-05-17 15:08:44 -0700608 return_status = QLA_FUNCTION_FAILED;
609 break;
610 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 msleep(1000);
612 if (time_after_eq(jiffies, loop_timeout)) {
613 return_status = QLA_FUNCTION_FAILED;
614 break;
615 }
616 }
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -0700617 return (return_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618}
619
Seokmann Ju5f3a9a22008-07-10 16:55:47 -0700620void
621qla2x00_abort_fcport_cmds(fc_port_t *fcport)
622{
623 int cnt;
624 unsigned long flags;
625 srb_t *sp;
626 scsi_qla_host_t *ha = fcport->ha;
627 scsi_qla_host_t *pha = to_qla_parent(ha);
628
629 spin_lock_irqsave(&pha->hardware_lock, flags);
630 for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
631 sp = pha->outstanding_cmds[cnt];
632 if (!sp)
633 continue;
634 if (sp->fcport != fcport)
635 continue;
636
637 spin_unlock_irqrestore(&pha->hardware_lock, flags);
638 if (ha->isp_ops->abort_command(ha, sp)) {
639 DEBUG2(qla_printk(KERN_WARNING, ha,
640 "Abort failed -- %lx\n", sp->cmd->serial_number));
641 } else {
642 if (qla2x00_eh_wait_on_command(ha, sp->cmd) !=
643 QLA_SUCCESS)
644 DEBUG2(qla_printk(KERN_WARNING, ha,
645 "Abort failed while waiting -- %lx\n",
646 sp->cmd->serial_number));
647
648 }
649 spin_lock_irqsave(&pha->hardware_lock, flags);
650 }
651 spin_unlock_irqrestore(&pha->hardware_lock, flags);
652}
653
Andrew Vasquez07db5182006-10-02 12:00:49 -0700654static void
655qla2x00_block_error_handler(struct scsi_cmnd *cmnd)
656{
657 struct Scsi_Host *shost = cmnd->device->host;
658 struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device));
659 unsigned long flags;
660
661 spin_lock_irqsave(shost->host_lock, flags);
662 while (rport->port_state == FC_PORTSTATE_BLOCKED) {
663 spin_unlock_irqrestore(shost->host_lock, flags);
664 msleep(1000);
665 spin_lock_irqsave(shost->host_lock, flags);
666 }
667 spin_unlock_irqrestore(shost->host_lock, flags);
668 return;
669}
670
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671/**************************************************************************
672* qla2xxx_eh_abort
673*
674* Description:
675* The abort function will abort the specified command.
676*
677* Input:
678* cmd = Linux SCSI command packet to be aborted.
679*
680* Returns:
681* Either SUCCESS or FAILED.
682*
683* Note:
Michael Reed2ea00202006-04-27 16:25:30 -0700684* Only return FAILED if command not returned by firmware.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685**************************************************************************/
Adrian Bunke5f82ab2006-11-08 19:55:50 -0800686static int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687qla2xxx_eh_abort(struct scsi_cmnd *cmd)
688{
Andrew Vasquezf363b942007-09-20 14:07:45 -0700689 scsi_qla_host_t *ha = shost_priv(cmd->device->host);
f4f051e2005-04-17 15:02:26 -0500690 srb_t *sp;
691 int ret, i;
692 unsigned int id, lun;
693 unsigned long serial;
Andrew Vasquez18e144d2005-05-27 15:04:47 -0700694 unsigned long flags;
Michael Reed2ea00202006-04-27 16:25:30 -0700695 int wait = 0;
Seokmann Ju2c3dfe32007-07-05 13:16:51 -0700696 scsi_qla_host_t *pha = to_qla_parent(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697
Andrew Vasquez07db5182006-10-02 12:00:49 -0700698 qla2x00_block_error_handler(cmd);
699
f4f051e2005-04-17 15:02:26 -0500700 if (!CMD_SP(cmd))
Michael Reed2ea00202006-04-27 16:25:30 -0700701 return SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702
Michael Reed2ea00202006-04-27 16:25:30 -0700703 ret = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704
f4f051e2005-04-17 15:02:26 -0500705 id = cmd->device->id;
706 lun = cmd->device->lun;
707 serial = cmd->serial_number;
708
709 /* Check active list for command command. */
Seokmann Ju2c3dfe32007-07-05 13:16:51 -0700710 spin_lock_irqsave(&pha->hardware_lock, flags);
f4f051e2005-04-17 15:02:26 -0500711 for (i = 1; i < MAX_OUTSTANDING_COMMANDS; i++) {
Seokmann Ju2c3dfe32007-07-05 13:16:51 -0700712 sp = pha->outstanding_cmds[i];
f4f051e2005-04-17 15:02:26 -0500713
714 if (sp == NULL)
715 continue;
716
717 if (sp->cmd != cmd)
718 continue;
719
Andrew Vasquez75bc4192006-05-17 15:09:22 -0700720 DEBUG2(printk("%s(%ld): aborting sp %p from RISC. pid=%ld.\n",
721 __func__, ha->host_no, sp, serial));
f4f051e2005-04-17 15:02:26 -0500722
Seokmann Ju2c3dfe32007-07-05 13:16:51 -0700723 spin_unlock_irqrestore(&pha->hardware_lock, flags);
Andrew Vasquezfd34f552007-07-19 15:06:00 -0700724 if (ha->isp_ops->abort_command(ha, sp)) {
f4f051e2005-04-17 15:02:26 -0500725 DEBUG2(printk("%s(%ld): abort_command "
726 "mbx failed.\n", __func__, ha->host_no));
727 } else {
728 DEBUG3(printk("%s(%ld): abort_command "
729 "mbx success.\n", __func__, ha->host_no));
Michael Reed2ea00202006-04-27 16:25:30 -0700730 wait = 1;
f4f051e2005-04-17 15:02:26 -0500731 }
Seokmann Ju2c3dfe32007-07-05 13:16:51 -0700732 spin_lock_irqsave(&pha->hardware_lock, flags);
f4f051e2005-04-17 15:02:26 -0500733
734 break;
735 }
Seokmann Ju2c3dfe32007-07-05 13:16:51 -0700736 spin_unlock_irqrestore(&pha->hardware_lock, flags);
f4f051e2005-04-17 15:02:26 -0500737
738 /* Wait for the command to be returned. */
Michael Reed2ea00202006-04-27 16:25:30 -0700739 if (wait) {
f4f051e2005-04-17 15:02:26 -0500740 if (qla2x00_eh_wait_on_command(ha, cmd) != QLA_SUCCESS) {
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -0700741 qla_printk(KERN_ERR, ha,
f4f051e2005-04-17 15:02:26 -0500742 "scsi(%ld:%d:%d): Abort handler timed out -- %lx "
743 "%x.\n", ha->host_no, id, lun, serial, ret);
Michael Reed2ea00202006-04-27 16:25:30 -0700744 ret = FAILED;
f4f051e2005-04-17 15:02:26 -0500745 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -0700748 qla_printk(KERN_INFO, ha,
Michael Reed2ea00202006-04-27 16:25:30 -0700749 "scsi(%ld:%d:%d): Abort command issued -- %d %lx %x.\n",
750 ha->host_no, id, lun, wait, serial, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751
f4f051e2005-04-17 15:02:26 -0500752 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753}
754
Andrew Vasquez523ec772008-04-03 13:13:24 -0700755enum nexus_wait_type {
756 WAIT_HOST = 0,
757 WAIT_TARGET,
758 WAIT_LUN,
759};
760
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761static int
Andrew Vasquez523ec772008-04-03 13:13:24 -0700762qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *ha, unsigned int t,
763 unsigned int l, enum nexus_wait_type type)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764{
Andrew Vasquez523ec772008-04-03 13:13:24 -0700765 int cnt, match, status;
766 srb_t *sp;
Andrew Vasquez18e144d2005-05-27 15:04:47 -0700767 unsigned long flags;
Seokmann Ju2c3dfe32007-07-05 13:16:51 -0700768 scsi_qla_host_t *pha = to_qla_parent(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769
Andrew Vasquez523ec772008-04-03 13:13:24 -0700770 status = QLA_SUCCESS;
771 spin_lock_irqsave(&pha->hardware_lock, flags);
772 for (cnt = 1; status == QLA_SUCCESS && cnt < MAX_OUTSTANDING_COMMANDS;
773 cnt++) {
Seokmann Ju2c3dfe32007-07-05 13:16:51 -0700774 sp = pha->outstanding_cmds[cnt];
Andrew Vasquez523ec772008-04-03 13:13:24 -0700775 if (!sp)
776 continue;
777 if (ha->vp_idx != sp->ha->vp_idx)
778 continue;
779 match = 0;
780 switch (type) {
781 case WAIT_HOST:
782 match = 1;
783 break;
784 case WAIT_TARGET:
785 match = sp->cmd->device->id == t;
786 break;
787 case WAIT_LUN:
788 match = (sp->cmd->device->id == t &&
789 sp->cmd->device->lun == l);
790 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 }
Andrew Vasquez523ec772008-04-03 13:13:24 -0700792 if (!match)
793 continue;
794
795 spin_unlock_irqrestore(&pha->hardware_lock, flags);
796 status = qla2x00_eh_wait_on_command(ha, sp->cmd);
797 spin_lock_irqsave(&pha->hardware_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 }
Andrew Vasquez523ec772008-04-03 13:13:24 -0700799 spin_unlock_irqrestore(&pha->hardware_lock, flags);
800
801 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802}
803
Andrew Vasquez523ec772008-04-03 13:13:24 -0700804static char *reset_errors[] = {
805 "HBA not online",
806 "HBA not ready",
807 "Task management failed",
808 "Waiting for command completions",
809};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810
Andrew Vasquez523ec772008-04-03 13:13:24 -0700811static int
812__qla2xxx_eh_generic_reset(char *name, enum nexus_wait_type type,
813 struct scsi_cmnd *cmd, int (*do_reset)(struct fc_port *, unsigned int))
814{
815 scsi_qla_host_t *ha = shost_priv(cmd->device->host);
816 fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
817 int err;
818
819 qla2x00_block_error_handler(cmd);
820
821 if (!fcport)
822 return FAILED;
823
824 qla_printk(KERN_INFO, ha, "scsi(%ld:%d:%d): %s RESET ISSUED.\n",
825 ha->host_no, cmd->device->id, cmd->device->lun, name);
826
827 err = 0;
828 if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS)
829 goto eh_reset_failed;
830 err = 1;
831 if (qla2x00_wait_for_loop_ready(ha) != QLA_SUCCESS)
832 goto eh_reset_failed;
833 err = 2;
834 if (do_reset(fcport, cmd->device->lun) != QLA_SUCCESS)
835 goto eh_reset_failed;
836 err = 3;
837 if (qla2x00_eh_wait_for_pending_commands(ha, cmd->device->id,
838 cmd->device->lun, type) != QLA_SUCCESS)
839 goto eh_reset_failed;
840
841 qla_printk(KERN_INFO, ha, "scsi(%ld:%d:%d): %s RESET SUCCEEDED.\n",
842 ha->host_no, cmd->device->id, cmd->device->lun, name);
843
844 return SUCCESS;
845
846 eh_reset_failed:
847 qla_printk(KERN_INFO, ha, "scsi(%ld:%d:%d): %s RESET FAILED: %s.\n",
848 ha->host_no, cmd->device->id, cmd->device->lun, name,
849 reset_errors[err]);
850 return FAILED;
851}
852
Adrian Bunke5f82ab2006-11-08 19:55:50 -0800853static int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854qla2xxx_eh_device_reset(struct scsi_cmnd *cmd)
855{
Andrew Vasquezf363b942007-09-20 14:07:45 -0700856 scsi_qla_host_t *ha = shost_priv(cmd->device->host);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857
Andrew Vasquez523ec772008-04-03 13:13:24 -0700858 return __qla2xxx_eh_generic_reset("DEVICE", WAIT_LUN, cmd,
859 ha->isp_ops->lun_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860}
861
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862static int
Andrew Vasquez523ec772008-04-03 13:13:24 -0700863qla2xxx_eh_target_reset(struct scsi_cmnd *cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864{
Andrew Vasquez523ec772008-04-03 13:13:24 -0700865 scsi_qla_host_t *ha = shost_priv(cmd->device->host);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866
Andrew Vasquez523ec772008-04-03 13:13:24 -0700867 return __qla2xxx_eh_generic_reset("TARGET", WAIT_TARGET, cmd,
868 ha->isp_ops->target_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869}
870
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871/**************************************************************************
872* qla2xxx_eh_bus_reset
873*
874* Description:
875* The bus reset function will reset the bus and abort any executing
876* commands.
877*
878* Input:
879* cmd = Linux SCSI command packet of the command that cause the
880* bus reset.
881*
882* Returns:
883* SUCCESS/FAILURE (defined as macro in scsi.h).
884*
885**************************************************************************/
Adrian Bunke5f82ab2006-11-08 19:55:50 -0800886static int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd)
888{
Andrew Vasquezf363b942007-09-20 14:07:45 -0700889 scsi_qla_host_t *ha = shost_priv(cmd->device->host);
Seokmann Ju2c3dfe32007-07-05 13:16:51 -0700890 scsi_qla_host_t *pha = to_qla_parent(ha);
bdf79622005-04-17 15:06:53 -0500891 fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
Seokmann Ju2c3dfe32007-07-05 13:16:51 -0700892 int ret = FAILED;
f4f051e2005-04-17 15:02:26 -0500893 unsigned int id, lun;
894 unsigned long serial;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895
Andrew Vasquez07db5182006-10-02 12:00:49 -0700896 qla2x00_block_error_handler(cmd);
897
f4f051e2005-04-17 15:02:26 -0500898 id = cmd->device->id;
899 lun = cmd->device->lun;
900 serial = cmd->serial_number;
901
Vladislav Bolkhovitinb0328be2006-08-01 13:48:15 -0700902 if (!fcport)
f4f051e2005-04-17 15:02:26 -0500903 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904
905 qla_printk(KERN_INFO, ha,
f4f051e2005-04-17 15:02:26 -0500906 "scsi(%ld:%d:%d): LOOP RESET ISSUED.\n", ha->host_no, id, lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS) {
909 DEBUG2(printk("%s failed:board disabled\n",__func__));
f4f051e2005-04-17 15:02:26 -0500910 goto eh_bus_reset_done;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 }
912
913 if (qla2x00_wait_for_loop_ready(ha) == QLA_SUCCESS) {
f4f051e2005-04-17 15:02:26 -0500914 if (qla2x00_loop_reset(ha) == QLA_SUCCESS)
915 ret = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 }
f4f051e2005-04-17 15:02:26 -0500917 if (ret == FAILED)
918 goto eh_bus_reset_done;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919
Andrew Vasquez9a41a622005-09-20 13:25:53 -0700920 /* Flush outstanding commands. */
Andrew Vasquez523ec772008-04-03 13:13:24 -0700921 if (qla2x00_eh_wait_for_pending_commands(pha, 0, 0, WAIT_HOST) !=
922 QLA_SUCCESS)
Andrew Vasquez9a41a622005-09-20 13:25:53 -0700923 ret = FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924
f4f051e2005-04-17 15:02:26 -0500925eh_bus_reset_done:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 qla_printk(KERN_INFO, ha, "%s: reset %s\n", __func__,
f4f051e2005-04-17 15:02:26 -0500927 (ret == FAILED) ? "failed" : "succeded");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928
f4f051e2005-04-17 15:02:26 -0500929 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930}
931
932/**************************************************************************
933* qla2xxx_eh_host_reset
934*
935* Description:
936* The reset function will reset the Adapter.
937*
938* Input:
939* cmd = Linux SCSI command packet of the command that cause the
940* adapter reset.
941*
942* Returns:
943* Either SUCCESS or FAILED.
944*
945* Note:
946**************************************************************************/
Adrian Bunke5f82ab2006-11-08 19:55:50 -0800947static int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
949{
Andrew Vasquezf363b942007-09-20 14:07:45 -0700950 scsi_qla_host_t *ha = shost_priv(cmd->device->host);
bdf79622005-04-17 15:06:53 -0500951 fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
Seokmann Ju2c3dfe32007-07-05 13:16:51 -0700952 int ret = FAILED;
f4f051e2005-04-17 15:02:26 -0500953 unsigned int id, lun;
954 unsigned long serial;
Seokmann Ju2c3dfe32007-07-05 13:16:51 -0700955 scsi_qla_host_t *pha = to_qla_parent(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956
Andrew Vasquez07db5182006-10-02 12:00:49 -0700957 qla2x00_block_error_handler(cmd);
958
f4f051e2005-04-17 15:02:26 -0500959 id = cmd->device->id;
960 lun = cmd->device->lun;
961 serial = cmd->serial_number;
962
Vladislav Bolkhovitinb0328be2006-08-01 13:48:15 -0700963 if (!fcport)
f4f051e2005-04-17 15:02:26 -0500964 return ret;
965
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 qla_printk(KERN_INFO, ha,
f4f051e2005-04-17 15:02:26 -0500967 "scsi(%ld:%d:%d): ADAPTER RESET ISSUED.\n", ha->host_no, id, lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS)
f4f051e2005-04-17 15:02:26 -0500970 goto eh_host_reset_lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971
972 /*
973 * Fixme-may be dpc thread is active and processing
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -0700974 * loop_resync,so wait a while for it to
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 * be completed and then issue big hammer.Otherwise
976 * it may cause I/O failure as big hammer marks the
977 * devices as lost kicking of the port_down_timer
978 * while dpc is stuck for the mailbox to complete.
979 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 qla2x00_wait_for_loop_ready(ha);
Seokmann Ju2c3dfe32007-07-05 13:16:51 -0700981 set_bit(ABORT_ISP_ACTIVE, &pha->dpc_flags);
982 if (qla2x00_abort_isp(pha)) {
983 clear_bit(ABORT_ISP_ACTIVE, &pha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 /* failed. schedule dpc to try */
Seokmann Ju2c3dfe32007-07-05 13:16:51 -0700985 set_bit(ISP_ABORT_NEEDED, &pha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986
987 if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS)
f4f051e2005-04-17 15:02:26 -0500988 goto eh_host_reset_lock;
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -0700989 }
Seokmann Ju2c3dfe32007-07-05 13:16:51 -0700990 clear_bit(ABORT_ISP_ACTIVE, &pha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 /* Waiting for our command in done_queue to be returned to OS.*/
Andrew Vasquez523ec772008-04-03 13:13:24 -0700993 if (qla2x00_eh_wait_for_pending_commands(pha, 0, 0, WAIT_HOST) ==
994 QLA_SUCCESS)
f4f051e2005-04-17 15:02:26 -0500995 ret = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996
Seokmann Ju2c3dfe32007-07-05 13:16:51 -0700997 if (ha->parent)
998 qla2x00_vp_abort_isp(ha);
999
f4f051e2005-04-17 15:02:26 -05001000eh_host_reset_lock:
f4f051e2005-04-17 15:02:26 -05001001 qla_printk(KERN_INFO, ha, "%s: reset %s\n", __func__,
1002 (ret == FAILED) ? "failed" : "succeded");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003
f4f051e2005-04-17 15:02:26 -05001004 return ret;
1005}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006
1007/*
1008* qla2x00_loop_reset
1009* Issue loop reset.
1010*
1011* Input:
1012* ha = adapter block pointer.
1013*
1014* Returns:
1015* 0 = success
1016*/
Andrew Vasqueza4722cf2008-01-17 09:02:12 -08001017int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018qla2x00_loop_reset(scsi_qla_host_t *ha)
1019{
Andrew Vasquez0c8c39a2006-12-13 19:20:30 -08001020 int ret;
bdf79622005-04-17 15:06:53 -05001021 struct fc_port *fcport;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022
Andrew Vasquez0c8c39a2006-12-13 19:20:30 -08001023 if (ha->flags.enable_lip_full_login) {
1024 ret = qla2x00_full_login_lip(ha);
1025 if (ret != QLA_SUCCESS) {
1026 DEBUG2_3(printk("%s(%ld): bus_reset failed: "
1027 "full_login_lip=%d.\n", __func__, ha->host_no,
1028 ret));
1029 }
1030 atomic_set(&ha->loop_state, LOOP_DOWN);
1031 atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME);
1032 qla2x00_mark_all_devices_lost(ha, 0);
1033 qla2x00_wait_for_loop_ready(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 }
1035
Andrew Vasquez0c8c39a2006-12-13 19:20:30 -08001036 if (ha->flags.enable_lip_reset) {
1037 ret = qla2x00_lip_reset(ha);
1038 if (ret != QLA_SUCCESS) {
1039 DEBUG2_3(printk("%s(%ld): bus_reset failed: "
1040 "lip_reset=%d.\n", __func__, ha->host_no, ret));
1041 }
1042 qla2x00_wait_for_loop_ready(ha);
1043 }
1044
1045 if (ha->flags.enable_target_reset) {
bdf79622005-04-17 15:06:53 -05001046 list_for_each_entry(fcport, &ha->fcports, list) {
1047 if (fcport->port_type != FCT_TARGET)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 continue;
1049
Andrew Vasquez523ec772008-04-03 13:13:24 -07001050 ret = ha->isp_ops->target_reset(fcport, 0);
Andrew Vasquez0c8c39a2006-12-13 19:20:30 -08001051 if (ret != QLA_SUCCESS) {
1052 DEBUG2_3(printk("%s(%ld): bus_reset failed: "
1053 "target_reset=%d d_id=%x.\n", __func__,
1054 ha->host_no, ret, fcport->d_id.b24));
1055 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 }
1057 }
1058
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 /* Issue marker command only when we are going to start the I/O */
1060 ha->marker_needed = 1;
1061
Andrew Vasquez0c8c39a2006-12-13 19:20:30 -08001062 return QLA_SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063}
1064
Andrew Vasquezdf4bf0b2008-01-31 12:33:46 -08001065void
1066qla2x00_abort_all_cmds(scsi_qla_host_t *ha, int res)
1067{
1068 int cnt;
1069 unsigned long flags;
1070 srb_t *sp;
1071
1072 spin_lock_irqsave(&ha->hardware_lock, flags);
1073 for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
1074 sp = ha->outstanding_cmds[cnt];
1075 if (sp) {
1076 ha->outstanding_cmds[cnt] = NULL;
1077 sp->flags = 0;
1078 sp->cmd->result = res;
1079 sp->cmd->host_scribble = (unsigned char *)NULL;
1080 qla2x00_sp_compl(ha, sp);
1081 }
1082 }
1083 spin_unlock_irqrestore(&ha->hardware_lock, flags);
1084}
1085
f4f051e2005-04-17 15:02:26 -05001086static int
1087qla2xxx_slave_alloc(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088{
bdf79622005-04-17 15:06:53 -05001089 struct fc_rport *rport = starget_to_rport(scsi_target(sdev));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090
James.Smart@Emulex.Com19a7b4a2005-10-18 12:03:35 -04001091 if (!rport || fc_remote_port_chkready(rport))
f4f051e2005-04-17 15:02:26 -05001092 return -ENXIO;
1093
James.Smart@Emulex.Com19a7b4a2005-10-18 12:03:35 -04001094 sdev->hostdata = *(fc_port_t **)rport->dd_data;
f4f051e2005-04-17 15:02:26 -05001095
1096 return 0;
1097}
1098
1099static int
1100qla2xxx_slave_configure(struct scsi_device *sdev)
1101{
Andrew Vasquezf363b942007-09-20 14:07:45 -07001102 scsi_qla_host_t *ha = shost_priv(sdev->host);
8482e1182005-04-17 15:04:54 -05001103 struct fc_rport *rport = starget_to_rport(sdev->sdev_target);
1104
f4f051e2005-04-17 15:02:26 -05001105 if (sdev->tagged_supported)
Andrew Vasquezdf7baa52006-10-13 09:33:39 -07001106 scsi_activate_tcq(sdev, ha->max_q_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 else
Andrew Vasquezdf7baa52006-10-13 09:33:39 -07001108 scsi_deactivate_tcq(sdev, ha->max_q_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109
Andrew Vasquez85821c92008-07-10 16:55:48 -07001110 rport->dev_loss_tmo = ha->port_down_retry_count;
8482e1182005-04-17 15:04:54 -05001111
f4f051e2005-04-17 15:02:26 -05001112 return 0;
1113}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114
f4f051e2005-04-17 15:02:26 -05001115static void
1116qla2xxx_slave_destroy(struct scsi_device *sdev)
1117{
1118 sdev->hostdata = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119}
1120
Andrew Vasquezce7e4af2005-08-26 19:09:30 -07001121static int
1122qla2x00_change_queue_depth(struct scsi_device *sdev, int qdepth)
1123{
1124 scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
1125 return sdev->queue_depth;
1126}
1127
1128static int
1129qla2x00_change_queue_type(struct scsi_device *sdev, int tag_type)
1130{
1131 if (sdev->tagged_supported) {
1132 scsi_set_tag_type(sdev, tag_type);
1133 if (tag_type)
1134 scsi_activate_tcq(sdev, sdev->queue_depth);
1135 else
1136 scsi_deactivate_tcq(sdev, sdev->queue_depth);
1137 } else
1138 tag_type = 0;
1139
1140 return tag_type;
1141}
1142
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143/**
1144 * qla2x00_config_dma_addressing() - Configure OS DMA addressing method.
1145 * @ha: HA context
1146 *
1147 * At exit, the @ha's flags.enable_64bit_addressing set to indicated
1148 * supported addressing method.
1149 */
1150static void
1151qla2x00_config_dma_addressing(scsi_qla_host_t *ha)
1152{
Andrew Vasquez7524f9b2005-08-26 19:08:00 -07001153 /* Assume a 32bit DMA mask. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 ha->flags.enable_64bit_addressing = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155
Andrew Vasquez7524f9b2005-08-26 19:08:00 -07001156 if (!dma_set_mask(&ha->pdev->dev, DMA_64BIT_MASK)) {
1157 /* Any upper-dword bits set? */
1158 if (MSD(dma_get_required_mask(&ha->pdev->dev)) &&
1159 !pci_set_consistent_dma_mask(ha->pdev, DMA_64BIT_MASK)) {
1160 /* Ok, a 64bit DMA mask is applicable. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 ha->flags.enable_64bit_addressing = 1;
Andrew Vasquezfd34f552007-07-19 15:06:00 -07001162 ha->isp_ops->calc_req_entries = qla2x00_calc_iocbs_64;
1163 ha->isp_ops->build_iocbs = qla2x00_build_scsi_iocbs_64;
Andrew Vasquez7524f9b2005-08-26 19:08:00 -07001164 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 }
Andrew Vasquez7524f9b2005-08-26 19:08:00 -07001167
1168 dma_set_mask(&ha->pdev->dev, DMA_32BIT_MASK);
1169 pci_set_consistent_dma_mask(ha->pdev, DMA_32BIT_MASK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170}
1171
Andrew Vasquezfd34f552007-07-19 15:06:00 -07001172static void
1173qla2x00_enable_intrs(scsi_qla_host_t *ha)
1174{
1175 unsigned long flags = 0;
1176 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
1177
1178 spin_lock_irqsave(&ha->hardware_lock, flags);
1179 ha->interrupts_on = 1;
1180 /* enable risc and host interrupts */
1181 WRT_REG_WORD(&reg->ictrl, ICR_EN_INT | ICR_EN_RISC);
1182 RD_REG_WORD(&reg->ictrl);
1183 spin_unlock_irqrestore(&ha->hardware_lock, flags);
1184
1185}
1186
1187static void
1188qla2x00_disable_intrs(scsi_qla_host_t *ha)
1189{
1190 unsigned long flags = 0;
1191 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
1192
1193 spin_lock_irqsave(&ha->hardware_lock, flags);
1194 ha->interrupts_on = 0;
1195 /* disable risc and host interrupts */
1196 WRT_REG_WORD(&reg->ictrl, 0);
1197 RD_REG_WORD(&reg->ictrl);
1198 spin_unlock_irqrestore(&ha->hardware_lock, flags);
1199}
1200
1201static void
1202qla24xx_enable_intrs(scsi_qla_host_t *ha)
1203{
1204 unsigned long flags = 0;
1205 struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
1206
1207 spin_lock_irqsave(&ha->hardware_lock, flags);
1208 ha->interrupts_on = 1;
1209 WRT_REG_DWORD(&reg->ictrl, ICRX_EN_RISC_INT);
1210 RD_REG_DWORD(&reg->ictrl);
1211 spin_unlock_irqrestore(&ha->hardware_lock, flags);
1212}
1213
1214static void
1215qla24xx_disable_intrs(scsi_qla_host_t *ha)
1216{
1217 unsigned long flags = 0;
1218 struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
1219
1220 spin_lock_irqsave(&ha->hardware_lock, flags);
1221 ha->interrupts_on = 0;
1222 WRT_REG_DWORD(&reg->ictrl, 0);
1223 RD_REG_DWORD(&reg->ictrl);
1224 spin_unlock_irqrestore(&ha->hardware_lock, flags);
1225}
1226
1227static struct isp_operations qla2100_isp_ops = {
1228 .pci_config = qla2100_pci_config,
1229 .reset_chip = qla2x00_reset_chip,
1230 .chip_diag = qla2x00_chip_diag,
1231 .config_rings = qla2x00_config_rings,
1232 .reset_adapter = qla2x00_reset_adapter,
1233 .nvram_config = qla2x00_nvram_config,
1234 .update_fw_options = qla2x00_update_fw_options,
1235 .load_risc = qla2x00_load_risc,
1236 .pci_info_str = qla2x00_pci_info_str,
1237 .fw_version_str = qla2x00_fw_version_str,
1238 .intr_handler = qla2100_intr_handler,
1239 .enable_intrs = qla2x00_enable_intrs,
1240 .disable_intrs = qla2x00_disable_intrs,
1241 .abort_command = qla2x00_abort_command,
Andrew Vasquez523ec772008-04-03 13:13:24 -07001242 .target_reset = qla2x00_abort_target,
1243 .lun_reset = qla2x00_lun_reset,
Andrew Vasquezfd34f552007-07-19 15:06:00 -07001244 .fabric_login = qla2x00_login_fabric,
1245 .fabric_logout = qla2x00_fabric_logout,
1246 .calc_req_entries = qla2x00_calc_iocbs_32,
1247 .build_iocbs = qla2x00_build_scsi_iocbs_32,
1248 .prep_ms_iocb = qla2x00_prep_ms_iocb,
1249 .prep_ms_fdmi_iocb = qla2x00_prep_ms_fdmi_iocb,
1250 .read_nvram = qla2x00_read_nvram_data,
1251 .write_nvram = qla2x00_write_nvram_data,
1252 .fw_dump = qla2100_fw_dump,
1253 .beacon_on = NULL,
1254 .beacon_off = NULL,
1255 .beacon_blink = NULL,
1256 .read_optrom = qla2x00_read_optrom_data,
1257 .write_optrom = qla2x00_write_optrom_data,
1258 .get_flash_version = qla2x00_get_flash_version,
1259};
1260
1261static struct isp_operations qla2300_isp_ops = {
1262 .pci_config = qla2300_pci_config,
1263 .reset_chip = qla2x00_reset_chip,
1264 .chip_diag = qla2x00_chip_diag,
1265 .config_rings = qla2x00_config_rings,
1266 .reset_adapter = qla2x00_reset_adapter,
1267 .nvram_config = qla2x00_nvram_config,
1268 .update_fw_options = qla2x00_update_fw_options,
1269 .load_risc = qla2x00_load_risc,
1270 .pci_info_str = qla2x00_pci_info_str,
1271 .fw_version_str = qla2x00_fw_version_str,
1272 .intr_handler = qla2300_intr_handler,
1273 .enable_intrs = qla2x00_enable_intrs,
1274 .disable_intrs = qla2x00_disable_intrs,
1275 .abort_command = qla2x00_abort_command,
Andrew Vasquez523ec772008-04-03 13:13:24 -07001276 .target_reset = qla2x00_abort_target,
1277 .lun_reset = qla2x00_lun_reset,
Andrew Vasquezfd34f552007-07-19 15:06:00 -07001278 .fabric_login = qla2x00_login_fabric,
1279 .fabric_logout = qla2x00_fabric_logout,
1280 .calc_req_entries = qla2x00_calc_iocbs_32,
1281 .build_iocbs = qla2x00_build_scsi_iocbs_32,
1282 .prep_ms_iocb = qla2x00_prep_ms_iocb,
1283 .prep_ms_fdmi_iocb = qla2x00_prep_ms_fdmi_iocb,
1284 .read_nvram = qla2x00_read_nvram_data,
1285 .write_nvram = qla2x00_write_nvram_data,
1286 .fw_dump = qla2300_fw_dump,
1287 .beacon_on = qla2x00_beacon_on,
1288 .beacon_off = qla2x00_beacon_off,
1289 .beacon_blink = qla2x00_beacon_blink,
1290 .read_optrom = qla2x00_read_optrom_data,
1291 .write_optrom = qla2x00_write_optrom_data,
1292 .get_flash_version = qla2x00_get_flash_version,
1293};
1294
1295static struct isp_operations qla24xx_isp_ops = {
1296 .pci_config = qla24xx_pci_config,
1297 .reset_chip = qla24xx_reset_chip,
1298 .chip_diag = qla24xx_chip_diag,
1299 .config_rings = qla24xx_config_rings,
1300 .reset_adapter = qla24xx_reset_adapter,
1301 .nvram_config = qla24xx_nvram_config,
1302 .update_fw_options = qla24xx_update_fw_options,
1303 .load_risc = qla24xx_load_risc,
1304 .pci_info_str = qla24xx_pci_info_str,
1305 .fw_version_str = qla24xx_fw_version_str,
1306 .intr_handler = qla24xx_intr_handler,
1307 .enable_intrs = qla24xx_enable_intrs,
1308 .disable_intrs = qla24xx_disable_intrs,
1309 .abort_command = qla24xx_abort_command,
Andrew Vasquez523ec772008-04-03 13:13:24 -07001310 .target_reset = qla24xx_abort_target,
1311 .lun_reset = qla24xx_lun_reset,
Andrew Vasquezfd34f552007-07-19 15:06:00 -07001312 .fabric_login = qla24xx_login_fabric,
1313 .fabric_logout = qla24xx_fabric_logout,
1314 .calc_req_entries = NULL,
1315 .build_iocbs = NULL,
1316 .prep_ms_iocb = qla24xx_prep_ms_iocb,
1317 .prep_ms_fdmi_iocb = qla24xx_prep_ms_fdmi_iocb,
1318 .read_nvram = qla24xx_read_nvram_data,
1319 .write_nvram = qla24xx_write_nvram_data,
1320 .fw_dump = qla24xx_fw_dump,
1321 .beacon_on = qla24xx_beacon_on,
1322 .beacon_off = qla24xx_beacon_off,
1323 .beacon_blink = qla24xx_beacon_blink,
1324 .read_optrom = qla24xx_read_optrom_data,
1325 .write_optrom = qla24xx_write_optrom_data,
1326 .get_flash_version = qla24xx_get_flash_version,
1327};
1328
Andrew Vasquezc3a2f0d2007-07-19 20:37:34 -07001329static struct isp_operations qla25xx_isp_ops = {
1330 .pci_config = qla25xx_pci_config,
1331 .reset_chip = qla24xx_reset_chip,
1332 .chip_diag = qla24xx_chip_diag,
1333 .config_rings = qla24xx_config_rings,
1334 .reset_adapter = qla24xx_reset_adapter,
1335 .nvram_config = qla24xx_nvram_config,
1336 .update_fw_options = qla24xx_update_fw_options,
1337 .load_risc = qla24xx_load_risc,
1338 .pci_info_str = qla24xx_pci_info_str,
1339 .fw_version_str = qla24xx_fw_version_str,
1340 .intr_handler = qla24xx_intr_handler,
1341 .enable_intrs = qla24xx_enable_intrs,
1342 .disable_intrs = qla24xx_disable_intrs,
1343 .abort_command = qla24xx_abort_command,
Andrew Vasquez523ec772008-04-03 13:13:24 -07001344 .target_reset = qla24xx_abort_target,
1345 .lun_reset = qla24xx_lun_reset,
Andrew Vasquezc3a2f0d2007-07-19 20:37:34 -07001346 .fabric_login = qla24xx_login_fabric,
1347 .fabric_logout = qla24xx_fabric_logout,
1348 .calc_req_entries = NULL,
1349 .build_iocbs = NULL,
1350 .prep_ms_iocb = qla24xx_prep_ms_iocb,
1351 .prep_ms_fdmi_iocb = qla24xx_prep_ms_fdmi_iocb,
1352 .read_nvram = qla25xx_read_nvram_data,
1353 .write_nvram = qla25xx_write_nvram_data,
1354 .fw_dump = qla25xx_fw_dump,
1355 .beacon_on = qla24xx_beacon_on,
1356 .beacon_off = qla24xx_beacon_off,
1357 .beacon_blink = qla24xx_beacon_blink,
Andrew Vasquez338c9162007-09-20 14:07:33 -07001358 .read_optrom = qla25xx_read_optrom_data,
Andrew Vasquezc3a2f0d2007-07-19 20:37:34 -07001359 .write_optrom = qla24xx_write_optrom_data,
1360 .get_flash_version = qla24xx_get_flash_version,
1361};
1362
andrew.vasquez@qlogic.comea5b6382006-03-09 14:27:08 -08001363static inline void
1364qla2x00_set_isp_flags(scsi_qla_host_t *ha)
1365{
1366 ha->device_type = DT_EXTENDED_IDS;
1367 switch (ha->pdev->device) {
1368 case PCI_DEVICE_ID_QLOGIC_ISP2100:
1369 ha->device_type |= DT_ISP2100;
1370 ha->device_type &= ~DT_EXTENDED_IDS;
Andrew Vasquez441d1072006-05-17 15:09:34 -07001371 ha->fw_srisc_address = RISC_START_ADDRESS_2100;
andrew.vasquez@qlogic.comea5b6382006-03-09 14:27:08 -08001372 break;
1373 case PCI_DEVICE_ID_QLOGIC_ISP2200:
1374 ha->device_type |= DT_ISP2200;
1375 ha->device_type &= ~DT_EXTENDED_IDS;
Andrew Vasquez441d1072006-05-17 15:09:34 -07001376 ha->fw_srisc_address = RISC_START_ADDRESS_2100;
andrew.vasquez@qlogic.comea5b6382006-03-09 14:27:08 -08001377 break;
1378 case PCI_DEVICE_ID_QLOGIC_ISP2300:
1379 ha->device_type |= DT_ISP2300;
andrew.vasquez@qlogic.com4a59f712006-03-09 14:27:39 -08001380 ha->device_type |= DT_ZIO_SUPPORTED;
Andrew Vasquez441d1072006-05-17 15:09:34 -07001381 ha->fw_srisc_address = RISC_START_ADDRESS_2300;
andrew.vasquez@qlogic.comea5b6382006-03-09 14:27:08 -08001382 break;
1383 case PCI_DEVICE_ID_QLOGIC_ISP2312:
1384 ha->device_type |= DT_ISP2312;
andrew.vasquez@qlogic.com4a59f712006-03-09 14:27:39 -08001385 ha->device_type |= DT_ZIO_SUPPORTED;
Andrew Vasquez441d1072006-05-17 15:09:34 -07001386 ha->fw_srisc_address = RISC_START_ADDRESS_2300;
andrew.vasquez@qlogic.comea5b6382006-03-09 14:27:08 -08001387 break;
1388 case PCI_DEVICE_ID_QLOGIC_ISP2322:
1389 ha->device_type |= DT_ISP2322;
andrew.vasquez@qlogic.com4a59f712006-03-09 14:27:39 -08001390 ha->device_type |= DT_ZIO_SUPPORTED;
andrew.vasquez@qlogic.comea5b6382006-03-09 14:27:08 -08001391 if (ha->pdev->subsystem_vendor == 0x1028 &&
1392 ha->pdev->subsystem_device == 0x0170)
1393 ha->device_type |= DT_OEM_001;
Andrew Vasquez441d1072006-05-17 15:09:34 -07001394 ha->fw_srisc_address = RISC_START_ADDRESS_2300;
andrew.vasquez@qlogic.comea5b6382006-03-09 14:27:08 -08001395 break;
1396 case PCI_DEVICE_ID_QLOGIC_ISP6312:
1397 ha->device_type |= DT_ISP6312;
Andrew Vasquez441d1072006-05-17 15:09:34 -07001398 ha->fw_srisc_address = RISC_START_ADDRESS_2300;
andrew.vasquez@qlogic.comea5b6382006-03-09 14:27:08 -08001399 break;
1400 case PCI_DEVICE_ID_QLOGIC_ISP6322:
1401 ha->device_type |= DT_ISP6322;
Andrew Vasquez441d1072006-05-17 15:09:34 -07001402 ha->fw_srisc_address = RISC_START_ADDRESS_2300;
andrew.vasquez@qlogic.comea5b6382006-03-09 14:27:08 -08001403 break;
1404 case PCI_DEVICE_ID_QLOGIC_ISP2422:
1405 ha->device_type |= DT_ISP2422;
andrew.vasquez@qlogic.com4a59f712006-03-09 14:27:39 -08001406 ha->device_type |= DT_ZIO_SUPPORTED;
Andrew Vasqueze4289242007-07-19 15:05:56 -07001407 ha->device_type |= DT_FWI2;
Andrew Vasquezc76f2c02007-07-19 15:05:57 -07001408 ha->device_type |= DT_IIDMA;
Andrew Vasquez441d1072006-05-17 15:09:34 -07001409 ha->fw_srisc_address = RISC_START_ADDRESS_2400;
andrew.vasquez@qlogic.comea5b6382006-03-09 14:27:08 -08001410 break;
1411 case PCI_DEVICE_ID_QLOGIC_ISP2432:
1412 ha->device_type |= DT_ISP2432;
andrew.vasquez@qlogic.com4a59f712006-03-09 14:27:39 -08001413 ha->device_type |= DT_ZIO_SUPPORTED;
Andrew Vasqueze4289242007-07-19 15:05:56 -07001414 ha->device_type |= DT_FWI2;
Andrew Vasquezc76f2c02007-07-19 15:05:57 -07001415 ha->device_type |= DT_IIDMA;
Andrew Vasquez441d1072006-05-17 15:09:34 -07001416 ha->fw_srisc_address = RISC_START_ADDRESS_2400;
andrew.vasquez@qlogic.comea5b6382006-03-09 14:27:08 -08001417 break;
Harihara Kadayam4d4df192008-04-03 13:13:26 -07001418 case PCI_DEVICE_ID_QLOGIC_ISP8432:
1419 ha->device_type |= DT_ISP8432;
1420 ha->device_type |= DT_ZIO_SUPPORTED;
1421 ha->device_type |= DT_FWI2;
1422 ha->device_type |= DT_IIDMA;
1423 ha->fw_srisc_address = RISC_START_ADDRESS_2400;
1424 break;
andrew.vasquez@qlogic.com044cc6c2006-03-09 14:27:13 -08001425 case PCI_DEVICE_ID_QLOGIC_ISP5422:
1426 ha->device_type |= DT_ISP5422;
Andrew Vasqueze4289242007-07-19 15:05:56 -07001427 ha->device_type |= DT_FWI2;
Andrew Vasquez441d1072006-05-17 15:09:34 -07001428 ha->fw_srisc_address = RISC_START_ADDRESS_2400;
andrew.vasquez@qlogic.comea5b6382006-03-09 14:27:08 -08001429 break;
andrew.vasquez@qlogic.com044cc6c2006-03-09 14:27:13 -08001430 case PCI_DEVICE_ID_QLOGIC_ISP5432:
1431 ha->device_type |= DT_ISP5432;
Andrew Vasqueze4289242007-07-19 15:05:56 -07001432 ha->device_type |= DT_FWI2;
Andrew Vasquez441d1072006-05-17 15:09:34 -07001433 ha->fw_srisc_address = RISC_START_ADDRESS_2400;
andrew.vasquez@qlogic.comea5b6382006-03-09 14:27:08 -08001434 break;
Andrew Vasquezc3a2f0d2007-07-19 20:37:34 -07001435 case PCI_DEVICE_ID_QLOGIC_ISP2532:
1436 ha->device_type |= DT_ISP2532;
1437 ha->device_type |= DT_ZIO_SUPPORTED;
1438 ha->device_type |= DT_FWI2;
1439 ha->device_type |= DT_IIDMA;
andrew.vasquez@qlogic.comea5b6382006-03-09 14:27:08 -08001440 ha->fw_srisc_address = RISC_START_ADDRESS_2400;
1441 break;
1442 }
1443}
1444
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445static int
1446qla2x00_iospace_config(scsi_qla_host_t *ha)
1447{
Andrew Vasquez37765412008-01-17 09:02:09 -08001448 resource_size_t pio;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449
Andrew Vasquez285d0322007-10-19 15:59:17 -07001450 if (pci_request_selected_regions(ha->pdev, ha->bars,
1451 QLA2XXX_DRIVER_NAME)) {
1452 qla_printk(KERN_WARNING, ha,
1453 "Failed to reserve PIO/MMIO regions (%s)\n",
1454 pci_name(ha->pdev));
1455
1456 goto iospace_error_exit;
1457 }
1458 if (!(ha->bars & 1))
1459 goto skip_pio;
1460
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461 /* We only need PIO for Flash operations on ISP2312 v2 chips. */
1462 pio = pci_resource_start(ha->pdev, 0);
Andrew Vasquez37765412008-01-17 09:02:09 -08001463 if (pci_resource_flags(ha->pdev, 0) & IORESOURCE_IO) {
1464 if (pci_resource_len(ha->pdev, 0) < MIN_IOBASE_LEN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 qla_printk(KERN_WARNING, ha,
1466 "Invalid PCI I/O region size (%s)...\n",
1467 pci_name(ha->pdev));
1468 pio = 0;
1469 }
1470 } else {
1471 qla_printk(KERN_WARNING, ha,
1472 "region #0 not a PIO resource (%s)...\n",
1473 pci_name(ha->pdev));
1474 pio = 0;
1475 }
Andrew Vasquez285d0322007-10-19 15:59:17 -07001476 ha->pio_address = pio;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477
Andrew Vasquez285d0322007-10-19 15:59:17 -07001478skip_pio:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 /* Use MMIO operations for all accesses. */
Andrew Vasquez37765412008-01-17 09:02:09 -08001480 if (!(pci_resource_flags(ha->pdev, 1) & IORESOURCE_MEM)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 qla_printk(KERN_ERR, ha,
Andrew Vasquez37765412008-01-17 09:02:09 -08001482 "region #1 not an MMIO resource (%s), aborting\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 pci_name(ha->pdev));
1484 goto iospace_error_exit;
1485 }
Andrew Vasquez37765412008-01-17 09:02:09 -08001486 if (pci_resource_len(ha->pdev, 1) < MIN_IOBASE_LEN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487 qla_printk(KERN_ERR, ha,
1488 "Invalid PCI mem region size (%s), aborting\n",
1489 pci_name(ha->pdev));
1490 goto iospace_error_exit;
1491 }
1492
Andrew Vasquez37765412008-01-17 09:02:09 -08001493 ha->iobase = ioremap(pci_resource_start(ha->pdev, 1), MIN_IOBASE_LEN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494 if (!ha->iobase) {
1495 qla_printk(KERN_ERR, ha,
1496 "cannot remap MMIO (%s), aborting\n", pci_name(ha->pdev));
1497
1498 goto iospace_error_exit;
1499 }
1500
1501 return (0);
1502
1503iospace_error_exit:
1504 return (-ENOMEM);
1505}
1506
Andrew Vasquezabbd8872005-07-06 10:30:05 -07001507static void
Andrew Vasquez1e99e332006-11-22 08:24:48 -08001508qla2xxx_scan_start(struct Scsi_Host *shost)
1509{
Andrew Vasquezf363b942007-09-20 14:07:45 -07001510 scsi_qla_host_t *ha = shost_priv(shost);
Andrew Vasquez1e99e332006-11-22 08:24:48 -08001511
1512 set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
1513 set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
1514 set_bit(RSCN_UPDATE, &ha->dpc_flags);
1515}
1516
1517static int
1518qla2xxx_scan_finished(struct Scsi_Host *shost, unsigned long time)
1519{
Andrew Vasquezf363b942007-09-20 14:07:45 -07001520 scsi_qla_host_t *ha = shost_priv(shost);
Andrew Vasquez1e99e332006-11-22 08:24:48 -08001521
1522 if (!ha->host)
1523 return 1;
1524 if (time > ha->loop_reset_delay * HZ)
1525 return 1;
1526
1527 return atomic_read(&ha->loop_state) == LOOP_READY;
1528}
1529
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530/*
1531 * PCI driver interface
1532 */
Andrew Vasquez7ee61392006-06-23 16:11:22 -07001533static int __devinit
1534qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535{
Andrew Vasqueza1541d52005-06-09 17:21:28 -07001536 int ret = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 struct Scsi_Host *host;
1538 scsi_qla_host_t *ha;
Andrew Vasquez29856e22007-08-12 18:22:52 -07001539 char pci_info[30];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 char fw_str[30];
Andrew Vasquez54333832005-11-09 15:49:04 -08001541 struct scsi_host_template *sht;
Benjamin Herrenschmidt09483912007-12-20 15:28:09 +11001542 int bars, mem_only = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543
Andrew Vasquez285d0322007-10-19 15:59:17 -07001544 bars = pci_select_bars(pdev, IORESOURCE_MEM | IORESOURCE_IO);
1545 sht = &qla2x00_driver_template;
1546 if (pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2422 ||
1547 pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2432 ||
Harihara Kadayam4d4df192008-04-03 13:13:26 -07001548 pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8432 ||
Andrew Vasquez285d0322007-10-19 15:59:17 -07001549 pdev->device == PCI_DEVICE_ID_QLOGIC_ISP5422 ||
1550 pdev->device == PCI_DEVICE_ID_QLOGIC_ISP5432 ||
1551 pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2532) {
1552 bars = pci_select_bars(pdev, IORESOURCE_MEM);
1553 sht = &qla24xx_driver_template;
Benjamin Herrenschmidt09483912007-12-20 15:28:09 +11001554 mem_only = 1;
Andrew Vasquez285d0322007-10-19 15:59:17 -07001555 }
1556
Benjamin Herrenschmidt09483912007-12-20 15:28:09 +11001557 if (mem_only) {
1558 if (pci_enable_device_mem(pdev))
1559 goto probe_out;
1560 } else {
1561 if (pci_enable_device(pdev))
1562 goto probe_out;
1563 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564
Seokmann Ju14e660e2007-09-20 14:07:36 -07001565 if (pci_find_aer_capability(pdev))
1566 if (pci_enable_pcie_error_reporting(pdev))
1567 goto probe_out;
1568
Andrew Vasquez54333832005-11-09 15:49:04 -08001569 host = scsi_host_alloc(sht, sizeof(scsi_qla_host_t));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 if (host == NULL) {
1571 printk(KERN_WARNING
1572 "qla2xxx: Couldn't allocate host from scsi layer!\n");
1573 goto probe_disable_device;
1574 }
1575
1576 /* Clear our data area */
Andrew Vasquezf363b942007-09-20 14:07:45 -07001577 ha = shost_priv(host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578 memset(ha, 0, sizeof(scsi_qla_host_t));
1579
1580 ha->pdev = pdev;
1581 ha->host = host;
1582 ha->host_no = host->host_no;
Andrew Vasquezcb630672006-05-17 15:09:45 -07001583 sprintf(ha->host_str, "%s_%ld", QLA2XXX_DRIVER_NAME, ha->host_no);
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07001584 ha->parent = NULL;
Andrew Vasquez285d0322007-10-19 15:59:17 -07001585 ha->bars = bars;
Benjamin Herrenschmidt09483912007-12-20 15:28:09 +11001586 ha->mem_only = mem_only;
Andrew Vasquezdf4bf0b2008-01-31 12:33:46 -08001587 spin_lock_init(&ha->hardware_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588
andrew.vasquez@qlogic.comea5b6382006-03-09 14:27:08 -08001589 /* Set ISP-type information. */
1590 qla2x00_set_isp_flags(ha);
1591
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592 /* Configure PCI I/O space */
1593 ret = qla2x00_iospace_config(ha);
Andrew Vasqueza1541d52005-06-09 17:21:28 -07001594 if (ret)
1595 goto probe_failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597 qla_printk(KERN_INFO, ha,
Andrew Vasquez54333832005-11-09 15:49:04 -08001598 "Found an ISP%04X, irq %d, iobase 0x%p\n", pdev->device, pdev->irq,
1599 ha->iobase);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 ha->prev_topology = 0;
Andrew Vasquezfca29702005-07-06 10:31:47 -07001602 ha->init_cb_size = sizeof(init_cb_t);
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07001603 ha->mgmt_svr_loop_id = MANAGEMENT_SERVER + ha->vp_idx;
Andrew Vasquezd8b45212006-10-02 12:00:43 -07001604 ha->link_data_rate = PORT_SPEED_UNKNOWN;
andrew.vasquez@qlogic.com854165f2006-01-31 16:05:17 -08001605 ha->optrom_size = OPTROM_SIZE_2300;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606
Andrew Vasquezdf7baa52006-10-13 09:33:39 -07001607 ha->max_q_depth = MAX_Q_DEPTH;
1608 if (ql2xmaxqdepth != 0 && ql2xmaxqdepth <= 0xffffU)
1609 ha->max_q_depth = ql2xmaxqdepth;
1610
Andrew Vasquezabbd8872005-07-06 10:30:05 -07001611 /* Assign ISP specific operations. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612 if (IS_QLA2100(ha)) {
Andrew Vasquez 354d6b22005-04-23 02:47:27 -04001613 host->max_id = MAX_TARGETS_2100;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614 ha->mbx_count = MAILBOX_REGISTER_COUNT_2100;
1615 ha->request_q_length = REQUEST_ENTRY_CNT_2100;
1616 ha->response_q_length = RESPONSE_ENTRY_CNT_2100;
1617 ha->last_loop_id = SNS_LAST_LOOP_ID_2100;
1618 host->sg_tablesize = 32;
Andrew Vasquezabbd8872005-07-06 10:30:05 -07001619 ha->gid_list_info_size = 4;
Andrew Vasquezfd34f552007-07-19 15:06:00 -07001620 ha->isp_ops = &qla2100_isp_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 } else if (IS_QLA2200(ha)) {
Andrew Vasquez 354d6b22005-04-23 02:47:27 -04001622 host->max_id = MAX_TARGETS_2200;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 ha->mbx_count = MAILBOX_REGISTER_COUNT;
1624 ha->request_q_length = REQUEST_ENTRY_CNT_2200;
1625 ha->response_q_length = RESPONSE_ENTRY_CNT_2100;
1626 ha->last_loop_id = SNS_LAST_LOOP_ID_2100;
Andrew Vasquezabbd8872005-07-06 10:30:05 -07001627 ha->gid_list_info_size = 4;
Andrew Vasquezfd34f552007-07-19 15:06:00 -07001628 ha->isp_ops = &qla2100_isp_ops;
Andrew Vasquezfca29702005-07-06 10:31:47 -07001629 } else if (IS_QLA23XX(ha)) {
Andrew Vasquez 354d6b22005-04-23 02:47:27 -04001630 host->max_id = MAX_TARGETS_2200;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 ha->mbx_count = MAILBOX_REGISTER_COUNT;
1632 ha->request_q_length = REQUEST_ENTRY_CNT_2200;
1633 ha->response_q_length = RESPONSE_ENTRY_CNT_2300;
1634 ha->last_loop_id = SNS_LAST_LOOP_ID_2300;
Andrew Vasquezabbd8872005-07-06 10:30:05 -07001635 ha->gid_list_info_size = 6;
andrew.vasquez@qlogic.com854165f2006-01-31 16:05:17 -08001636 if (IS_QLA2322(ha) || IS_QLA6322(ha))
1637 ha->optrom_size = OPTROM_SIZE_2322;
Andrew Vasquezfd34f552007-07-19 15:06:00 -07001638 ha->isp_ops = &qla2300_isp_ops;
Harihara Kadayam4d4df192008-04-03 13:13:26 -07001639 } else if (IS_QLA24XX_TYPE(ha)) {
Andrew Vasquezfca29702005-07-06 10:31:47 -07001640 host->max_id = MAX_TARGETS_2200;
1641 ha->mbx_count = MAILBOX_REGISTER_COUNT;
1642 ha->request_q_length = REQUEST_ENTRY_CNT_24XX;
1643 ha->response_q_length = RESPONSE_ENTRY_CNT_2300;
1644 ha->last_loop_id = SNS_LAST_LOOP_ID_2300;
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07001645 ha->init_cb_size = sizeof(struct mid_init_cb_24xx);
1646 ha->mgmt_svr_loop_id = 10 + ha->vp_idx;
Andrew Vasquezfca29702005-07-06 10:31:47 -07001647 ha->gid_list_info_size = 8;
andrew.vasquez@qlogic.com854165f2006-01-31 16:05:17 -08001648 ha->optrom_size = OPTROM_SIZE_24XX;
Andrew Vasquezfd34f552007-07-19 15:06:00 -07001649 ha->isp_ops = &qla24xx_isp_ops;
Andrew Vasquezc3a2f0d2007-07-19 20:37:34 -07001650 } else if (IS_QLA25XX(ha)) {
1651 host->max_id = MAX_TARGETS_2200;
1652 ha->mbx_count = MAILBOX_REGISTER_COUNT;
1653 ha->request_q_length = REQUEST_ENTRY_CNT_24XX;
1654 ha->response_q_length = RESPONSE_ENTRY_CNT_2300;
1655 ha->last_loop_id = SNS_LAST_LOOP_ID_2300;
1656 ha->init_cb_size = sizeof(struct mid_init_cb_24xx);
1657 ha->mgmt_svr_loop_id = 10 + ha->vp_idx;
1658 ha->gid_list_info_size = 8;
1659 ha->optrom_size = OPTROM_SIZE_25XX;
1660 ha->isp_ops = &qla25xx_isp_ops;
Andrew Vasquezcb8dacb2008-04-03 13:13:19 -07001661 ha->hw_event_start = PCI_FUNC(pdev->devfn) ?
1662 FA_HW_EVENT1_ADDR: FA_HW_EVENT0_ADDR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 }
1664 host->can_queue = ha->request_q_length + 128;
1665
1666 /* load the F/W, read paramaters, and init the H/W */
1667 ha->instance = num_hosts;
1668
matthias@kaehlcke.net6c2f5272008-05-12 22:21:11 -07001669 mutex_init(&ha->vport_lock);
Marcus Barrow0b05a1f2008-01-17 09:02:13 -08001670 init_completion(&ha->mbx_cmd_comp);
1671 complete(&ha->mbx_cmd_comp);
1672 init_completion(&ha->mbx_intr_comp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673
1674 INIT_LIST_HEAD(&ha->list);
1675 INIT_LIST_HEAD(&ha->fcports);
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07001676 INIT_LIST_HEAD(&ha->vp_list);
Andrew Vasquez0971de72008-04-03 13:13:18 -07001677 INIT_LIST_HEAD(&ha->work_list);
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07001678
1679 set_bit(0, (unsigned long *) ha->vp_idx_map);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681 qla2x00_config_dma_addressing(ha);
1682 if (qla2x00_mem_alloc(ha)) {
1683 qla_printk(KERN_WARNING, ha,
1684 "[ERROR] Failed to allocate memory for adapter\n");
1685
Andrew Vasqueza1541d52005-06-09 17:21:28 -07001686 ret = -ENOMEM;
1687 goto probe_failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688 }
1689
Andrew Vasquez765140b2007-05-07 07:42:58 -07001690 if (qla2x00_initialize_adapter(ha)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691 qla_printk(KERN_WARNING, ha,
1692 "Failed to initialize adapter\n");
1693
1694 DEBUG2(printk("scsi(%ld): Failed to initialize adapter - "
1695 "Adapter flags %x.\n",
1696 ha->host_no, ha->device_flags));
1697
Andrew Vasqueza1541d52005-06-09 17:21:28 -07001698 ret = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 goto probe_failed;
1700 }
1701
1702 /*
1703 * Startup the kernel thread for this host adapter
1704 */
Christoph Hellwig39a11242006-02-14 18:46:22 +01001705 ha->dpc_thread = kthread_create(qla2x00_do_dpc, ha,
1706 "%s_dpc", ha->host_str);
1707 if (IS_ERR(ha->dpc_thread)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708 qla_printk(KERN_WARNING, ha,
1709 "Unable to start DPC thread!\n");
Christoph Hellwig39a11242006-02-14 18:46:22 +01001710 ret = PTR_ERR(ha->dpc_thread);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 goto probe_failed;
1712 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713
Andrew Vasqueza1541d52005-06-09 17:21:28 -07001714 host->this_id = 255;
1715 host->cmd_per_lun = 3;
1716 host->unique_id = ha->instance;
1717 host->max_cmd_len = MAX_CMDSZ;
Andrew Vasquez75bc4192006-05-17 15:09:22 -07001718 host->max_channel = MAX_BUSES - 1;
Andrew Vasqueza1541d52005-06-09 17:21:28 -07001719 host->max_lun = MAX_LUNS;
1720 host->transportt = qla2xxx_transport_template;
1721
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08001722 ret = qla2x00_request_irqs(ha);
1723 if (ret)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724 goto probe_failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725
1726 /* Initialized the timer */
1727 qla2x00_start_timer(ha, qla2x00_timer, WATCH_INTERVAL);
1728
1729 DEBUG2(printk("DEBUG: detect hba %ld at address = %p\n",
1730 ha->host_no, ha));
1731
Andrew Vasqueza1541d52005-06-09 17:21:28 -07001732 pci_set_drvdata(pdev, ha);
Andrew Vasquezd19044c2006-11-22 08:22:19 -08001733
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 ha->flags.init_done = 1;
Andrew Vasquezd19044c2006-11-22 08:22:19 -08001735 ha->flags.online = 1;
1736
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737 num_hosts++;
1738
Andrew Vasqueza1541d52005-06-09 17:21:28 -07001739 ret = scsi_add_host(host, &pdev->dev);
1740 if (ret)
1741 goto probe_failed;
1742
Andrew Vasquez1e99e332006-11-22 08:24:48 -08001743 scsi_scan_host(host);
1744
Andrew Vasqueza1541d52005-06-09 17:21:28 -07001745 qla2x00_alloc_sysfs_attr(ha);
1746
1747 qla2x00_init_host_attr(ha);
1748
Andrew Vasquezdf613b92008-01-17 09:02:17 -08001749 qla2x00_dfs_setup(ha);
1750
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 qla_printk(KERN_INFO, ha, "\n"
1752 " QLogic Fibre Channel HBA Driver: %s\n"
1753 " QLogic %s - %s\n"
Andrew Vasquez54333832005-11-09 15:49:04 -08001754 " ISP%04X: %s @ %s hdma%c, host#=%ld, fw=%s\n",
1755 qla2x00_version_str, ha->model_number,
1756 ha->model_desc ? ha->model_desc: "", pdev->device,
Andrew Vasquezfd34f552007-07-19 15:06:00 -07001757 ha->isp_ops->pci_info_str(ha, pci_info), pci_name(pdev),
Andrew Vasquez54333832005-11-09 15:49:04 -08001758 ha->flags.enable_64bit_addressing ? '+': '-', ha->host_no,
Andrew Vasquezfd34f552007-07-19 15:06:00 -07001759 ha->isp_ops->fw_version_str(ha, fw_str));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761 return 0;
1762
1763probe_failed:
1764 qla2x00_free_device(ha);
1765
1766 scsi_host_put(host);
1767
1768probe_disable_device:
1769 pci_disable_device(pdev);
1770
Andrew Vasqueza1541d52005-06-09 17:21:28 -07001771probe_out:
1772 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774
Adrian Bunk4c993f72008-01-14 00:55:16 -08001775static void
Andrew Vasquez7ee61392006-06-23 16:11:22 -07001776qla2x00_remove_one(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777{
1778 scsi_qla_host_t *ha;
1779
1780 ha = pci_get_drvdata(pdev);
1781
Andrew Vasquezdf613b92008-01-17 09:02:17 -08001782 qla2x00_dfs_remove(ha);
1783
Harihara Kadayam4d4df192008-04-03 13:13:26 -07001784 qla84xx_put_chip(ha);
1785
8482e1182005-04-17 15:04:54 -05001786 qla2x00_free_sysfs_attr(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787
bdf79622005-04-17 15:06:53 -05001788 fc_remove_host(ha->host);
1789
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790 scsi_remove_host(ha->host);
1791
1792 qla2x00_free_device(ha);
1793
1794 scsi_host_put(ha->host);
1795
Bernhard Walle665db932007-03-28 00:49:49 +02001796 pci_disable_device(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797 pci_set_drvdata(pdev, NULL);
1798}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799
1800static void
1801qla2x00_free_device(scsi_qla_host_t *ha)
1802{
Andrew Vasquezdf4bf0b2008-01-31 12:33:46 -08001803 qla2x00_abort_all_cmds(ha, DID_NO_CONNECT << 16);
1804
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 /* Disable timer */
1806 if (ha->timer_active)
1807 qla2x00_stop_timer(ha);
1808
Andrew Vasquezdf4bf0b2008-01-31 12:33:46 -08001809 ha->flags.online = 0;
1810
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811 /* Kill the kernel thread for this host */
Christoph Hellwig39a11242006-02-14 18:46:22 +01001812 if (ha->dpc_thread) {
1813 struct task_struct *t = ha->dpc_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814
Christoph Hellwig39a11242006-02-14 18:46:22 +01001815 /*
1816 * qla2xxx_wake_dpc checks for ->dpc_thread
1817 * so we need to zero it out.
1818 */
1819 ha->dpc_thread = NULL;
1820 kthread_stop(t);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821 }
1822
Andrew Vasquezdf613b92008-01-17 09:02:17 -08001823 if (ha->flags.fce_enabled)
1824 qla2x00_disable_fce_trace(ha, NULL, NULL);
1825
Andrew Vasqueza7a167b2006-06-23 16:10:29 -07001826 if (ha->eft)
Andrew Vasquez00b6bd22008-01-17 09:02:16 -08001827 qla2x00_disable_eft_trace(ha);
Andrew Vasqueza7a167b2006-06-23 16:10:29 -07001828
Andrew Vasquezf6ef3b12005-08-26 19:10:20 -07001829 /* Stop currently executing firmware. */
Andrew Vasquez18c6c122006-10-13 09:33:38 -07001830 qla2x00_try_to_stop_firmware(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831
Andrew Vasquezf6ef3b12005-08-26 19:10:20 -07001832 /* turn-off interrupts on the card */
1833 if (ha->interrupts_on)
Andrew Vasquezfd34f552007-07-19 15:06:00 -07001834 ha->isp_ops->disable_intrs(ha);
Andrew Vasquezf6ef3b12005-08-26 19:10:20 -07001835
1836 qla2x00_mem_free(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08001838 qla2x00_free_irqs(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839
1840 /* release io space registers */
1841 if (ha->iobase)
1842 iounmap(ha->iobase);
Andrew Vasquez285d0322007-10-19 15:59:17 -07001843 pci_release_selected_regions(ha->pdev, ha->bars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844}
1845
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08001846static inline void
1847qla2x00_schedule_rport_del(struct scsi_qla_host *ha, fc_port_t *fcport,
1848 int defer)
1849{
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08001850 struct fc_rport *rport;
1851
1852 if (!fcport->rport)
1853 return;
1854
1855 rport = fcport->rport;
1856 if (defer) {
Seokmann Ju5f3a9a22008-07-10 16:55:47 -07001857 spin_lock_irq(ha->host->host_lock);
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08001858 fcport->drport = rport;
Seokmann Ju5f3a9a22008-07-10 16:55:47 -07001859 spin_unlock_irq(ha->host->host_lock);
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08001860 set_bit(FCPORT_UPDATE_NEEDED, &ha->dpc_flags);
Seokmann Ju5f3a9a22008-07-10 16:55:47 -07001861 qla2xxx_wake_dpc(ha);
1862 } else
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08001863 fc_remote_port_delete(rport);
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08001864}
1865
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867 * qla2x00_mark_device_lost Updates fcport state when device goes offline.
1868 *
1869 * Input: ha = adapter block pointer. fcport = port structure pointer.
1870 *
1871 * Return: None.
1872 *
1873 * Context:
1874 */
1875void qla2x00_mark_device_lost(scsi_qla_host_t *ha, fc_port_t *fcport,
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08001876 int do_login, int defer)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877{
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07001878 if (atomic_read(&fcport->state) == FCS_ONLINE &&
1879 ha->vp_idx == fcport->vp_idx)
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08001880 qla2x00_schedule_rport_del(ha, fcport, defer);
James.Smart@Emulex.Com19a7b4a2005-10-18 12:03:35 -04001881
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07001882 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883 * We may need to retry the login, so don't change the state of the
1884 * port but do the retries.
1885 */
1886 if (atomic_read(&fcport->state) != FCS_DEVICE_DEAD)
1887 atomic_set(&fcport->state, FCS_DEVICE_LOST);
1888
1889 if (!do_login)
1890 return;
1891
1892 if (fcport->login_retry == 0) {
1893 fcport->login_retry = ha->login_retry_count;
1894 set_bit(RELOGIN_NEEDED, &ha->dpc_flags);
1895
1896 DEBUG(printk("scsi(%ld): Port login retry: "
1897 "%02x%02x%02x%02x%02x%02x%02x%02x, "
1898 "id = 0x%04x retry cnt=%d\n",
1899 ha->host_no,
1900 fcport->port_name[0],
1901 fcport->port_name[1],
1902 fcport->port_name[2],
1903 fcport->port_name[3],
1904 fcport->port_name[4],
1905 fcport->port_name[5],
1906 fcport->port_name[6],
1907 fcport->port_name[7],
1908 fcport->loop_id,
1909 fcport->login_retry));
1910 }
1911}
1912
1913/*
1914 * qla2x00_mark_all_devices_lost
1915 * Updates fcport state when device goes offline.
1916 *
1917 * Input:
1918 * ha = adapter block pointer.
1919 * fcport = port structure pointer.
1920 *
1921 * Return:
1922 * None.
1923 *
1924 * Context:
1925 */
1926void
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08001927qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha, int defer)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928{
1929 fc_port_t *fcport;
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07001930 scsi_qla_host_t *pha = to_qla_parent(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07001932 list_for_each_entry(fcport, &pha->fcports, list) {
1933 if (ha->vp_idx != 0 && ha->vp_idx != fcport->vp_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935 /*
1936 * No point in marking the device as lost, if the device is
1937 * already DEAD.
1938 */
1939 if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD)
1940 continue;
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07001941 if (atomic_read(&fcport->state) == FCS_ONLINE) {
1942 if (defer)
1943 qla2x00_schedule_rport_del(ha, fcport, defer);
1944 else if (ha->vp_idx == fcport->vp_idx)
1945 qla2x00_schedule_rport_del(ha, fcport, defer);
1946 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 atomic_set(&fcport->state, FCS_DEVICE_LOST);
1948 }
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08001949
Christoph Hellwig39a11242006-02-14 18:46:22 +01001950 if (defer)
1951 qla2xxx_wake_dpc(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952}
1953
1954/*
1955* qla2x00_mem_alloc
1956* Allocates adapter memory.
1957*
1958* Returns:
1959* 0 = success.
Andrew Vasqueze8711082008-01-31 12:33:48 -08001960* !0 = failure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961*/
Andrew Vasqueze8711082008-01-31 12:33:48 -08001962static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963qla2x00_mem_alloc(scsi_qla_host_t *ha)
1964{
1965 char name[16];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966
Andrew Vasqueze8711082008-01-31 12:33:48 -08001967 ha->request_ring = dma_alloc_coherent(&ha->pdev->dev,
1968 (ha->request_q_length + 1) * sizeof(request_t), &ha->request_dma,
1969 GFP_KERNEL);
1970 if (!ha->request_ring)
1971 goto fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972
Andrew Vasqueze8711082008-01-31 12:33:48 -08001973 ha->response_ring = dma_alloc_coherent(&ha->pdev->dev,
1974 (ha->response_q_length + 1) * sizeof(response_t),
1975 &ha->response_dma, GFP_KERNEL);
1976 if (!ha->response_ring)
1977 goto fail_free_request_ring;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001978
Andrew Vasqueze8711082008-01-31 12:33:48 -08001979 ha->gid_list = dma_alloc_coherent(&ha->pdev->dev, GID_LIST_SIZE,
1980 &ha->gid_list_dma, GFP_KERNEL);
1981 if (!ha->gid_list)
1982 goto fail_free_response_ring;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983
Andrew Vasqueze8711082008-01-31 12:33:48 -08001984 ha->init_cb = dma_alloc_coherent(&ha->pdev->dev, ha->init_cb_size,
1985 &ha->init_cb_dma, GFP_KERNEL);
1986 if (!ha->init_cb)
1987 goto fail_free_gid_list;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988
Andrew Vasqueze8711082008-01-31 12:33:48 -08001989 snprintf(name, sizeof(name), "%s_%ld", QLA2XXX_DRIVER_NAME,
1990 ha->host_no);
1991 ha->s_dma_pool = dma_pool_create(name, &ha->pdev->dev,
1992 DMA_POOL_SIZE, 8, 0);
1993 if (!ha->s_dma_pool)
1994 goto fail_free_init_cb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995
Andrew Vasqueze8711082008-01-31 12:33:48 -08001996 ha->srb_mempool = mempool_create_slab_pool(SRB_MIN_REQ, srb_cachep);
1997 if (!ha->srb_mempool)
1998 goto fail_free_s_dma_pool;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999
Andrew Vasqueze8711082008-01-31 12:33:48 -08002000 /* Get memory for cached NVRAM */
2001 ha->nvram = kzalloc(MAX_NVRAM_SIZE, GFP_KERNEL);
2002 if (!ha->nvram)
2003 goto fail_free_srb_mempool;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004
Andrew Vasqueze8711082008-01-31 12:33:48 -08002005 /* Allocate memory for SNS commands */
2006 if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
2007 /* Get consistent memory allocated for SNS commands */
2008 ha->sns_cmd = dma_alloc_coherent(&ha->pdev->dev,
2009 sizeof(struct sns_cmd_pkt), &ha->sns_cmd_dma, GFP_KERNEL);
2010 if (!ha->sns_cmd)
2011 goto fail_free_nvram;
2012 } else {
2013 /* Get consistent memory allocated for MS IOCB */
2014 ha->ms_iocb = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL,
2015 &ha->ms_iocb_dma);
2016 if (!ha->ms_iocb)
2017 goto fail_free_nvram;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002018
Andrew Vasqueze8711082008-01-31 12:33:48 -08002019 /* Get consistent memory allocated for CT SNS commands */
2020 ha->ct_sns = dma_alloc_coherent(&ha->pdev->dev,
2021 sizeof(struct ct_sns_pkt), &ha->ct_sns_dma, GFP_KERNEL);
2022 if (!ha->ct_sns)
2023 goto fail_free_ms_iocb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024 }
2025
Andrew Vasqueze8711082008-01-31 12:33:48 -08002026 return 0;
2027
2028fail_free_ms_iocb:
2029 dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma);
2030 ha->ms_iocb = NULL;
2031 ha->ms_iocb_dma = 0;
2032fail_free_nvram:
2033 kfree(ha->nvram);
2034 ha->nvram = NULL;
2035fail_free_srb_mempool:
2036 mempool_destroy(ha->srb_mempool);
2037 ha->srb_mempool = NULL;
2038fail_free_s_dma_pool:
2039 dma_pool_destroy(ha->s_dma_pool);
2040 ha->s_dma_pool = NULL;
2041fail_free_init_cb:
2042 dma_free_coherent(&ha->pdev->dev, ha->init_cb_size, ha->init_cb,
2043 ha->init_cb_dma);
2044 ha->init_cb = NULL;
2045 ha->init_cb_dma = 0;
2046fail_free_gid_list:
2047 dma_free_coherent(&ha->pdev->dev, GID_LIST_SIZE, ha->gid_list,
2048 ha->gid_list_dma);
2049 ha->gid_list = NULL;
2050 ha->gid_list_dma = 0;
2051fail_free_response_ring:
2052 dma_free_coherent(&ha->pdev->dev, (ha->response_q_length + 1) *
2053 sizeof(response_t), ha->response_ring, ha->response_dma);
2054 ha->response_ring = NULL;
2055 ha->response_dma = 0;
2056fail_free_request_ring:
2057 dma_free_coherent(&ha->pdev->dev, (ha->request_q_length + 1) *
2058 sizeof(request_t), ha->request_ring, ha->request_dma);
2059 ha->request_ring = NULL;
2060 ha->request_dma = 0;
2061fail:
2062 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063}
2064
2065/*
2066* qla2x00_mem_free
2067* Frees all adapter allocated memory.
2068*
2069* Input:
2070* ha = adapter block pointer.
2071*/
Adrian Bunka824ebb2008-01-17 09:02:15 -08002072static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073qla2x00_mem_free(scsi_qla_host_t *ha)
2074{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075 struct list_head *fcpl, *fcptemp;
2076 fc_port_t *fcport;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077
Andrew Vasqueze8711082008-01-31 12:33:48 -08002078 if (ha->srb_mempool)
2079 mempool_destroy(ha->srb_mempool);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080
Andrew Vasquezdf613b92008-01-17 09:02:17 -08002081 if (ha->fce)
2082 dma_free_coherent(&ha->pdev->dev, FCE_SIZE, ha->fce,
2083 ha->fce_dma);
2084
Andrew Vasqueza7a167b2006-06-23 16:10:29 -07002085 if (ha->fw_dump) {
2086 if (ha->eft)
2087 dma_free_coherent(&ha->pdev->dev,
2088 ntohl(ha->fw_dump->eft_size), ha->eft, ha->eft_dma);
2089 vfree(ha->fw_dump);
2090 }
2091
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092 if (ha->sns_cmd)
2093 dma_free_coherent(&ha->pdev->dev, sizeof(struct sns_cmd_pkt),
2094 ha->sns_cmd, ha->sns_cmd_dma);
2095
2096 if (ha->ct_sns)
2097 dma_free_coherent(&ha->pdev->dev, sizeof(struct ct_sns_pkt),
2098 ha->ct_sns, ha->ct_sns_dma);
2099
Andrew Vasquez88729e52006-06-23 16:10:50 -07002100 if (ha->sfp_data)
2101 dma_pool_free(ha->s_dma_pool, ha->sfp_data, ha->sfp_data_dma);
2102
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103 if (ha->ms_iocb)
2104 dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma);
2105
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106 if (ha->s_dma_pool)
2107 dma_pool_destroy(ha->s_dma_pool);
2108
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07002109 if (ha->init_cb)
2110 dma_free_coherent(&ha->pdev->dev, ha->init_cb_size,
2111 ha->init_cb, ha->init_cb_dma);
2112
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113 if (ha->gid_list)
2114 dma_free_coherent(&ha->pdev->dev, GID_LIST_SIZE, ha->gid_list,
2115 ha->gid_list_dma);
2116
2117 if (ha->response_ring)
2118 dma_free_coherent(&ha->pdev->dev,
2119 (ha->response_q_length + 1) * sizeof(response_t),
2120 ha->response_ring, ha->response_dma);
2121
2122 if (ha->request_ring)
2123 dma_free_coherent(&ha->pdev->dev,
2124 (ha->request_q_length + 1) * sizeof(request_t),
2125 ha->request_ring, ha->request_dma);
2126
Andrew Vasqueze8711082008-01-31 12:33:48 -08002127 ha->srb_mempool = NULL;
Andrew Vasqueza7a167b2006-06-23 16:10:29 -07002128 ha->eft = NULL;
2129 ha->eft_dma = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002130 ha->sns_cmd = NULL;
2131 ha->sns_cmd_dma = 0;
2132 ha->ct_sns = NULL;
2133 ha->ct_sns_dma = 0;
2134 ha->ms_iocb = NULL;
2135 ha->ms_iocb_dma = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002136 ha->init_cb = NULL;
2137 ha->init_cb_dma = 0;
2138
2139 ha->s_dma_pool = NULL;
2140
Linus Torvalds1da177e2005-04-16 15:20:36 -07002141 ha->gid_list = NULL;
2142 ha->gid_list_dma = 0;
2143
2144 ha->response_ring = NULL;
2145 ha->response_dma = 0;
2146 ha->request_ring = NULL;
2147 ha->request_dma = 0;
2148
2149 list_for_each_safe(fcpl, fcptemp, &ha->fcports) {
2150 fcport = list_entry(fcpl, fc_port_t, list);
2151
Linus Torvalds1da177e2005-04-16 15:20:36 -07002152 /* fc ports */
2153 list_del_init(&fcport->list);
2154 kfree(fcport);
2155 }
2156 INIT_LIST_HEAD(&ha->fcports);
2157
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158 ha->fw_dump = NULL;
Andrew Vasquezfca29702005-07-06 10:31:47 -07002159 ha->fw_dumped = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160 ha->fw_dump_reading = 0;
andrew.vasquez@qlogic.com854165f2006-01-31 16:05:17 -08002161
2162 vfree(ha->optrom_buffer);
Seokmann Ju53772a22007-07-30 11:01:07 -07002163 kfree(ha->nvram);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164}
2165
Adrian Bunk01ef66b2008-04-24 15:21:27 -07002166static struct qla_work_evt *
Andrew Vasquez0971de72008-04-03 13:13:18 -07002167qla2x00_alloc_work(struct scsi_qla_host *ha, enum qla_work_type type,
2168 int locked)
2169{
2170 struct qla_work_evt *e;
2171
2172 e = kzalloc(sizeof(struct qla_work_evt), locked ? GFP_ATOMIC:
2173 GFP_KERNEL);
2174 if (!e)
2175 return NULL;
2176
2177 INIT_LIST_HEAD(&e->list);
2178 e->type = type;
2179 e->flags = QLA_EVT_FLAG_FREE;
2180 return e;
2181}
2182
Adrian Bunk01ef66b2008-04-24 15:21:27 -07002183static int
Andrew Vasquez0971de72008-04-03 13:13:18 -07002184qla2x00_post_work(struct scsi_qla_host *ha, struct qla_work_evt *e, int locked)
2185{
2186 unsigned long flags;
Seokmann Ju08b95a12008-05-19 14:25:40 -07002187 scsi_qla_host_t *pha = to_qla_parent(ha);
Andrew Vasquez0971de72008-04-03 13:13:18 -07002188
2189 if (!locked)
Seokmann Ju08b95a12008-05-19 14:25:40 -07002190 spin_lock_irqsave(&pha->hardware_lock, flags);
Andrew Vasquez0971de72008-04-03 13:13:18 -07002191 list_add_tail(&e->list, &ha->work_list);
2192 qla2xxx_wake_dpc(ha);
2193 if (!locked)
Seokmann Ju08b95a12008-05-19 14:25:40 -07002194 spin_unlock_irqrestore(&pha->hardware_lock, flags);
Andrew Vasquez0971de72008-04-03 13:13:18 -07002195 return QLA_SUCCESS;
2196}
2197
2198int
2199qla2x00_post_aen_work(struct scsi_qla_host *ha, enum fc_host_event_code code,
2200 u32 data)
2201{
2202 struct qla_work_evt *e;
2203
2204 e = qla2x00_alloc_work(ha, QLA_EVT_AEN, 1);
2205 if (!e)
2206 return QLA_FUNCTION_FAILED;
2207
2208 e->u.aen.code = code;
2209 e->u.aen.data = data;
2210 return qla2x00_post_work(ha, e, 1);
2211}
2212
Andrew Vasquezcb8dacb2008-04-03 13:13:19 -07002213int
2214qla2x00_post_hwe_work(struct scsi_qla_host *ha, uint16_t code, uint16_t d1,
2215 uint16_t d2, uint16_t d3)
2216{
2217 struct qla_work_evt *e;
2218
2219 e = qla2x00_alloc_work(ha, QLA_EVT_HWE_LOG, 1);
2220 if (!e)
2221 return QLA_FUNCTION_FAILED;
2222
2223 e->u.hwe.code = code;
2224 e->u.hwe.d1 = d1;
2225 e->u.hwe.d2 = d2;
2226 e->u.hwe.d3 = d3;
2227 return qla2x00_post_work(ha, e, 1);
2228}
2229
Andrew Vasquez0971de72008-04-03 13:13:18 -07002230static void
2231qla2x00_do_work(struct scsi_qla_host *ha)
2232{
2233 struct qla_work_evt *e;
Seokmann Ju08b95a12008-05-19 14:25:40 -07002234 scsi_qla_host_t *pha = to_qla_parent(ha);
Andrew Vasquez0971de72008-04-03 13:13:18 -07002235
Seokmann Ju08b95a12008-05-19 14:25:40 -07002236 spin_lock_irq(&pha->hardware_lock);
Andrew Vasquez0971de72008-04-03 13:13:18 -07002237 while (!list_empty(&ha->work_list)) {
2238 e = list_entry(ha->work_list.next, struct qla_work_evt, list);
2239 list_del_init(&e->list);
Seokmann Ju08b95a12008-05-19 14:25:40 -07002240 spin_unlock_irq(&pha->hardware_lock);
Andrew Vasquez0971de72008-04-03 13:13:18 -07002241
2242 switch (e->type) {
2243 case QLA_EVT_AEN:
2244 fc_host_post_event(ha->host, fc_get_event_number(),
2245 e->u.aen.code, e->u.aen.data);
2246 break;
Andrew Vasquezcb8dacb2008-04-03 13:13:19 -07002247 case QLA_EVT_HWE_LOG:
2248 qla2xxx_hw_event_log(ha, e->u.hwe.code, e->u.hwe.d1,
2249 e->u.hwe.d2, e->u.hwe.d3);
2250 break;
Andrew Vasquez0971de72008-04-03 13:13:18 -07002251 }
2252 if (e->flags & QLA_EVT_FLAG_FREE)
2253 kfree(e);
Seokmann Ju08b95a12008-05-19 14:25:40 -07002254 spin_lock_irq(&pha->hardware_lock);
Andrew Vasquez0971de72008-04-03 13:13:18 -07002255 }
Seokmann Ju08b95a12008-05-19 14:25:40 -07002256 spin_unlock_irq(&pha->hardware_lock);
Andrew Vasquez0971de72008-04-03 13:13:18 -07002257}
2258
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259/**************************************************************************
2260* qla2x00_do_dpc
2261* This kernel thread is a task that is schedule by the interrupt handler
2262* to perform the background processing for interrupts.
2263*
2264* Notes:
2265* This task always run in the context of a kernel thread. It
2266* is kick-off by the driver's detect code and starts up
2267* up one per adapter. It immediately goes to sleep and waits for
2268* some fibre event. When either the interrupt handler or
2269* the timer routine detects a event it will one of the task
2270* bits then wake us up.
2271**************************************************************************/
2272static int
2273qla2x00_do_dpc(void *data)
2274{
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07002275 int rval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002276 scsi_qla_host_t *ha;
2277 fc_port_t *fcport;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002278 uint8_t status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279 uint16_t next_loopid;
Seokmann Ju99363ef2008-01-31 12:33:51 -08002280 struct scsi_qla_host *vha;
2281 int i;
2282
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283
2284 ha = (scsi_qla_host_t *)data;
2285
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286 set_user_nice(current, -20);
2287
Christoph Hellwig39a11242006-02-14 18:46:22 +01002288 while (!kthread_should_stop()) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289 DEBUG3(printk("qla2x00: DPC handler sleeping\n"));
2290
Christoph Hellwig39a11242006-02-14 18:46:22 +01002291 set_current_state(TASK_INTERRUPTIBLE);
2292 schedule();
2293 __set_current_state(TASK_RUNNING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294
2295 DEBUG3(printk("qla2x00: DPC handler waking up\n"));
2296
2297 /* Initialization not yet finished. Don't do anything yet. */
Christoph Hellwig39a11242006-02-14 18:46:22 +01002298 if (!ha->flags.init_done)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002299 continue;
2300
2301 DEBUG3(printk("scsi(%ld): DPC handler\n", ha->host_no));
2302
2303 ha->dpc_active = 1;
2304
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305 if (ha->flags.mbox_busy) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306 ha->dpc_active = 0;
2307 continue;
2308 }
2309
Andrew Vasquez0971de72008-04-03 13:13:18 -07002310 qla2x00_do_work(ha);
2311
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312 if (test_and_clear_bit(ISP_ABORT_NEEDED, &ha->dpc_flags)) {
2313
2314 DEBUG(printk("scsi(%ld): dpc: sched "
2315 "qla2x00_abort_isp ha = %p\n",
2316 ha->host_no, ha));
2317 if (!(test_and_set_bit(ABORT_ISP_ACTIVE,
2318 &ha->dpc_flags))) {
2319
2320 if (qla2x00_abort_isp(ha)) {
2321 /* failed. retry later */
2322 set_bit(ISP_ABORT_NEEDED,
2323 &ha->dpc_flags);
2324 }
2325 clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
2326 }
Seokmann Ju99363ef2008-01-31 12:33:51 -08002327
2328 for_each_mapped_vp_idx(ha, i) {
2329 list_for_each_entry(vha, &ha->vp_list,
2330 vp_list) {
2331 if (i == vha->vp_idx) {
2332 set_bit(ISP_ABORT_NEEDED,
2333 &vha->dpc_flags);
2334 break;
2335 }
2336 }
2337 }
2338
Linus Torvalds1da177e2005-04-16 15:20:36 -07002339 DEBUG(printk("scsi(%ld): dpc: qla2x00_abort_isp end\n",
2340 ha->host_no));
2341 }
2342
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08002343 if (test_and_clear_bit(FCPORT_UPDATE_NEEDED, &ha->dpc_flags))
2344 qla2x00_update_fcports(ha);
2345
Linus Torvalds1da177e2005-04-16 15:20:36 -07002346 if (test_and_clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags) &&
2347 (!(test_and_set_bit(RESET_ACTIVE, &ha->dpc_flags)))) {
2348
2349 DEBUG(printk("scsi(%ld): qla2x00_reset_marker()\n",
2350 ha->host_no));
2351
2352 qla2x00_rst_aen(ha);
2353 clear_bit(RESET_ACTIVE, &ha->dpc_flags);
2354 }
2355
2356 /* Retry each device up to login retry count */
2357 if ((test_and_clear_bit(RELOGIN_NEEDED, &ha->dpc_flags)) &&
2358 !test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags) &&
2359 atomic_read(&ha->loop_state) != LOOP_DOWN) {
2360
2361 DEBUG(printk("scsi(%ld): qla2x00_port_login()\n",
2362 ha->host_no));
2363
2364 next_loopid = 0;
2365 list_for_each_entry(fcport, &ha->fcports, list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366 /*
2367 * If the port is not ONLINE then try to login
2368 * to it if we haven't run out of retries.
2369 */
2370 if (atomic_read(&fcport->state) != FCS_ONLINE &&
2371 fcport->login_retry) {
2372
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373 if (fcport->flags & FCF_FABRIC_DEVICE) {
2374 if (fcport->flags &
2375 FCF_TAPE_PRESENT)
Andrew Vasquezfd34f552007-07-19 15:06:00 -07002376 ha->isp_ops->fabric_logout(
Andrew Vasquez1c7c6352005-07-06 10:30:57 -07002377 ha, fcport->loop_id,
2378 fcport->d_id.b.domain,
2379 fcport->d_id.b.area,
2380 fcport->d_id.b.al_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002381 status = qla2x00_fabric_login(
2382 ha, fcport, &next_loopid);
2383 } else
2384 status =
2385 qla2x00_local_device_login(
andrew.vasquez@qlogic.com9a52a572006-03-09 14:27:44 -08002386 ha, fcport);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387
Ravi Anand63a86512007-09-20 14:07:40 -07002388 fcport->login_retry--;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389 if (status == QLA_SUCCESS) {
2390 fcport->old_loop_id = fcport->loop_id;
2391
2392 DEBUG(printk("scsi(%ld): port login OK: logged in ID 0x%x\n",
2393 ha->host_no, fcport->loop_id));
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07002394
andrew.vasquez@qlogic.com052c40c2006-01-20 14:53:19 -08002395 qla2x00_update_fcport(ha,
2396 fcport);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397 } else if (status == 1) {
2398 set_bit(RELOGIN_NEEDED, &ha->dpc_flags);
2399 /* retry the login again */
2400 DEBUG(printk("scsi(%ld): Retrying %d login again loop_id 0x%x\n",
2401 ha->host_no,
2402 fcport->login_retry, fcport->loop_id));
2403 } else {
2404 fcport->login_retry = 0;
2405 }
Andrew Vasquez666301e2008-04-24 15:21:30 -07002406 if (fcport->login_retry == 0 && status != QLA_SUCCESS)
Ravi Anand63a86512007-09-20 14:07:40 -07002407 fcport->loop_id = FC_NO_LOOP_ID;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408 }
2409 if (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags))
2410 break;
2411 }
2412 DEBUG(printk("scsi(%ld): qla2x00_port_login - end\n",
2413 ha->host_no));
2414 }
2415
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416 if (test_and_clear_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) {
2417
2418 DEBUG(printk("scsi(%ld): qla2x00_loop_resync()\n",
2419 ha->host_no));
2420
2421 if (!(test_and_set_bit(LOOP_RESYNC_ACTIVE,
2422 &ha->dpc_flags))) {
2423
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07002424 rval = qla2x00_loop_resync(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002425
2426 clear_bit(LOOP_RESYNC_ACTIVE, &ha->dpc_flags);
2427 }
2428
2429 DEBUG(printk("scsi(%ld): qla2x00_loop_resync - end\n",
2430 ha->host_no));
2431 }
2432
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433 if (!ha->interrupts_on)
Andrew Vasquezfd34f552007-07-19 15:06:00 -07002434 ha->isp_ops->enable_intrs(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435
andrew.vasquez@qlogic.comf6df1442006-01-31 16:05:07 -08002436 if (test_and_clear_bit(BEACON_BLINK_NEEDED, &ha->dpc_flags))
Andrew Vasquezfd34f552007-07-19 15:06:00 -07002437 ha->isp_ops->beacon_blink(ha);
andrew.vasquez@qlogic.comf6df1442006-01-31 16:05:07 -08002438
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07002439 qla2x00_do_dpc_all_vps(ha);
2440
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441 ha->dpc_active = 0;
2442 } /* End of while(1) */
2443
2444 DEBUG(printk("scsi(%ld): DPC handler exiting\n", ha->host_no));
2445
2446 /*
2447 * Make sure that nobody tries to wake us up again.
2448 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449 ha->dpc_active = 0;
2450
Christoph Hellwig39a11242006-02-14 18:46:22 +01002451 return 0;
2452}
2453
2454void
2455qla2xxx_wake_dpc(scsi_qla_host_t *ha)
2456{
2457 if (ha->dpc_thread)
2458 wake_up_process(ha->dpc_thread);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459}
2460
2461/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462* qla2x00_rst_aen
2463* Processes asynchronous reset.
2464*
2465* Input:
2466* ha = adapter block pointer.
2467*/
2468static void
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07002469qla2x00_rst_aen(scsi_qla_host_t *ha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470{
2471 if (ha->flags.online && !ha->flags.reset_active &&
2472 !atomic_read(&ha->loop_down_timer) &&
2473 !(test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags))) {
2474 do {
2475 clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
2476
2477 /*
2478 * Issue marker command only when we are going to start
2479 * the I/O.
2480 */
2481 ha->marker_needed = 1;
2482 } while (!atomic_read(&ha->loop_down_timer) &&
2483 (test_bit(RESET_MARKER_NEEDED, &ha->dpc_flags)));
2484 }
2485}
2486
f4f051e2005-04-17 15:02:26 -05002487static void
2488qla2x00_sp_free_dma(scsi_qla_host_t *ha, srb_t *sp)
2489{
2490 struct scsi_cmnd *cmd = sp->cmd;
2491
2492 if (sp->flags & SRB_DMA_VALID) {
FUJITA Tomonori385d70b2007-05-26 01:55:38 +09002493 scsi_dma_unmap(cmd);
f4f051e2005-04-17 15:02:26 -05002494 sp->flags &= ~SRB_DMA_VALID;
2495 }
Andrew Vasquezfca29702005-07-06 10:31:47 -07002496 CMD_SP(cmd) = NULL;
f4f051e2005-04-17 15:02:26 -05002497}
2498
2499void
2500qla2x00_sp_compl(scsi_qla_host_t *ha, srb_t *sp)
2501{
2502 struct scsi_cmnd *cmd = sp->cmd;
2503
2504 qla2x00_sp_free_dma(ha, sp);
2505
f4f051e2005-04-17 15:02:26 -05002506 mempool_free(sp, ha->srb_mempool);
2507
2508 cmd->scsi_done(cmd);
2509}
bdf79622005-04-17 15:06:53 -05002510
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511/**************************************************************************
2512* qla2x00_timer
2513*
2514* Description:
2515* One second timer
2516*
2517* Context: Interrupt
2518***************************************************************************/
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07002519void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520qla2x00_timer(scsi_qla_host_t *ha)
2521{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522 unsigned long cpu_flags = 0;
2523 fc_port_t *fcport;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524 int start_dpc = 0;
2525 int index;
2526 srb_t *sp;
f4f051e2005-04-17 15:02:26 -05002527 int t;
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07002528 scsi_qla_host_t *pha = to_qla_parent(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529
2530 /*
2531 * Ports - Port down timer.
2532 *
2533 * Whenever, a port is in the LOST state we start decrementing its port
2534 * down timer every second until it reaches zero. Once it reaches zero
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07002535 * the port it marked DEAD.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536 */
2537 t = 0;
2538 list_for_each_entry(fcport, &ha->fcports, list) {
2539 if (fcport->port_type != FCT_TARGET)
2540 continue;
2541
2542 if (atomic_read(&fcport->state) == FCS_DEVICE_LOST) {
2543
2544 if (atomic_read(&fcport->port_down_timer) == 0)
2545 continue;
2546
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07002547 if (atomic_dec_and_test(&fcport->port_down_timer) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548 atomic_set(&fcport->state, FCS_DEVICE_DEAD);
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07002549
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550 DEBUG(printk("scsi(%ld): fcport-%d - port retry count: "
Andrew Vasquezfca29702005-07-06 10:31:47 -07002551 "%d remaining\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552 ha->host_no,
2553 t, atomic_read(&fcport->port_down_timer)));
2554 }
2555 t++;
2556 } /* End of for fcport */
2557
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558
2559 /* Loop down handler. */
2560 if (atomic_read(&ha->loop_down_timer) > 0 &&
2561 !(test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags)) && ha->flags.online) {
2562
2563 if (atomic_read(&ha->loop_down_timer) ==
2564 ha->loop_down_abort_time) {
2565
2566 DEBUG(printk("scsi(%ld): Loop Down - aborting the "
2567 "queues before time expire\n",
2568 ha->host_no));
2569
2570 if (!IS_QLA2100(ha) && ha->link_down_timeout)
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07002571 atomic_set(&ha->loop_state, LOOP_DEAD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572
2573 /* Schedule an ISP abort to return any tape commands. */
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07002574 /* NPIV - scan physical port only */
2575 if (!ha->parent) {
2576 spin_lock_irqsave(&ha->hardware_lock,
2577 cpu_flags);
2578 for (index = 1;
2579 index < MAX_OUTSTANDING_COMMANDS;
2580 index++) {
2581 fc_port_t *sfcp;
bdf79622005-04-17 15:06:53 -05002582
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07002583 sp = ha->outstanding_cmds[index];
2584 if (!sp)
2585 continue;
2586 sfcp = sp->fcport;
2587 if (!(sfcp->flags & FCF_TAPE_PRESENT))
2588 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002589
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07002590 set_bit(ISP_ABORT_NEEDED,
2591 &ha->dpc_flags);
2592 break;
2593 }
2594 spin_unlock_irqrestore(&ha->hardware_lock,
2595 cpu_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002596 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597 set_bit(ABORT_QUEUES_NEEDED, &ha->dpc_flags);
2598 start_dpc++;
2599 }
2600
2601 /* if the loop has been down for 4 minutes, reinit adapter */
2602 if (atomic_dec_and_test(&ha->loop_down_timer) != 0) {
2603 DEBUG(printk("scsi(%ld): Loop down exceed 4 mins - "
2604 "restarting queues.\n",
2605 ha->host_no));
2606
2607 set_bit(RESTART_QUEUES_NEEDED, &ha->dpc_flags);
2608 start_dpc++;
2609
Seokmann Ju463717e2008-04-03 13:13:29 -07002610 if (!(ha->device_flags & DFLG_NO_CABLE) &&
2611 !ha->parent) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612 DEBUG(printk("scsi(%ld): Loop down - "
2613 "aborting ISP.\n",
2614 ha->host_no));
2615 qla_printk(KERN_WARNING, ha,
2616 "Loop down - aborting ISP.\n");
2617
2618 set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
2619 }
2620 }
Andrew Vasquezfca29702005-07-06 10:31:47 -07002621 DEBUG3(printk("scsi(%ld): Loop Down - seconds remaining %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622 ha->host_no,
2623 atomic_read(&ha->loop_down_timer)));
2624 }
2625
andrew.vasquez@qlogic.comf6df1442006-01-31 16:05:07 -08002626 /* Check if beacon LED needs to be blinked */
2627 if (ha->beacon_blink_led == 1) {
2628 set_bit(BEACON_BLINK_NEEDED, &ha->dpc_flags);
2629 start_dpc++;
2630 }
2631
Andrew Vasquez550bf572008-04-24 15:21:23 -07002632 /* Process any deferred work. */
2633 if (!list_empty(&ha->work_list))
2634 start_dpc++;
2635
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636 /* Schedule the DPC routine if needed */
2637 if ((test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) ||
2638 test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags) ||
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08002639 test_bit(FCPORT_UPDATE_NEEDED, &ha->dpc_flags) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640 start_dpc ||
f4f051e2005-04-17 15:02:26 -05002641 test_bit(RESET_MARKER_NEEDED, &ha->dpc_flags) ||
andrew.vasquez@qlogic.comf6df1442006-01-31 16:05:07 -08002642 test_bit(BEACON_BLINK_NEEDED, &ha->dpc_flags) ||
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07002643 test_bit(VP_DPC_NEEDED, &ha->dpc_flags) ||
Christoph Hellwig39a11242006-02-14 18:46:22 +01002644 test_bit(RELOGIN_NEEDED, &ha->dpc_flags)))
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07002645 qla2xxx_wake_dpc(pha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646
2647 qla2x00_restart_timer(ha, WATCH_INTERVAL);
2648}
2649
Andrew Vasquez54333832005-11-09 15:49:04 -08002650/* Firmware interface routines. */
2651
Andrew Vasquezc3a2f0d2007-07-19 20:37:34 -07002652#define FW_BLOBS 6
Andrew Vasquez54333832005-11-09 15:49:04 -08002653#define FW_ISP21XX 0
2654#define FW_ISP22XX 1
2655#define FW_ISP2300 2
2656#define FW_ISP2322 3
andrew.vasquez@qlogic.com48c02fd2006-03-09 14:27:18 -08002657#define FW_ISP24XX 4
Andrew Vasquezc3a2f0d2007-07-19 20:37:34 -07002658#define FW_ISP25XX 5
Andrew Vasquez54333832005-11-09 15:49:04 -08002659
Andrew Vasquezbb8ee492006-10-02 12:00:48 -07002660#define FW_FILE_ISP21XX "ql2100_fw.bin"
2661#define FW_FILE_ISP22XX "ql2200_fw.bin"
2662#define FW_FILE_ISP2300 "ql2300_fw.bin"
2663#define FW_FILE_ISP2322 "ql2322_fw.bin"
2664#define FW_FILE_ISP24XX "ql2400_fw.bin"
Andrew Vasquezc3a2f0d2007-07-19 20:37:34 -07002665#define FW_FILE_ISP25XX "ql2500_fw.bin"
Andrew Vasquezbb8ee492006-10-02 12:00:48 -07002666
Daniel Walkere1e82b62008-05-12 22:21:10 -07002667static DEFINE_MUTEX(qla_fw_lock);
Andrew Vasquez54333832005-11-09 15:49:04 -08002668
2669static struct fw_blob qla_fw_blobs[FW_BLOBS] = {
Andrew Vasquezbb8ee492006-10-02 12:00:48 -07002670 { .name = FW_FILE_ISP21XX, .segs = { 0x1000, 0 }, },
2671 { .name = FW_FILE_ISP22XX, .segs = { 0x1000, 0 }, },
2672 { .name = FW_FILE_ISP2300, .segs = { 0x800, 0 }, },
2673 { .name = FW_FILE_ISP2322, .segs = { 0x800, 0x1c000, 0x1e000, 0 }, },
2674 { .name = FW_FILE_ISP24XX, },
Andrew Vasquezc3a2f0d2007-07-19 20:37:34 -07002675 { .name = FW_FILE_ISP25XX, },
Andrew Vasquez54333832005-11-09 15:49:04 -08002676};
2677
2678struct fw_blob *
2679qla2x00_request_firmware(scsi_qla_host_t *ha)
2680{
2681 struct fw_blob *blob;
2682
2683 blob = NULL;
2684 if (IS_QLA2100(ha)) {
2685 blob = &qla_fw_blobs[FW_ISP21XX];
2686 } else if (IS_QLA2200(ha)) {
2687 blob = &qla_fw_blobs[FW_ISP22XX];
andrew.vasquez@qlogic.com48c02fd2006-03-09 14:27:18 -08002688 } else if (IS_QLA2300(ha) || IS_QLA2312(ha) || IS_QLA6312(ha)) {
Andrew Vasquez54333832005-11-09 15:49:04 -08002689 blob = &qla_fw_blobs[FW_ISP2300];
andrew.vasquez@qlogic.com48c02fd2006-03-09 14:27:18 -08002690 } else if (IS_QLA2322(ha) || IS_QLA6322(ha)) {
Andrew Vasquez54333832005-11-09 15:49:04 -08002691 blob = &qla_fw_blobs[FW_ISP2322];
Harihara Kadayam4d4df192008-04-03 13:13:26 -07002692 } else if (IS_QLA24XX_TYPE(ha)) {
Andrew Vasquez54333832005-11-09 15:49:04 -08002693 blob = &qla_fw_blobs[FW_ISP24XX];
Andrew Vasquezc3a2f0d2007-07-19 20:37:34 -07002694 } else if (IS_QLA25XX(ha)) {
2695 blob = &qla_fw_blobs[FW_ISP25XX];
Andrew Vasquez54333832005-11-09 15:49:04 -08002696 }
2697
Daniel Walkere1e82b62008-05-12 22:21:10 -07002698 mutex_lock(&qla_fw_lock);
Andrew Vasquez54333832005-11-09 15:49:04 -08002699 if (blob->fw)
2700 goto out;
2701
2702 if (request_firmware(&blob->fw, blob->name, &ha->pdev->dev)) {
2703 DEBUG2(printk("scsi(%ld): Failed to load firmware image "
2704 "(%s).\n", ha->host_no, blob->name));
2705 blob->fw = NULL;
2706 blob = NULL;
2707 goto out;
2708 }
2709
2710out:
Daniel Walkere1e82b62008-05-12 22:21:10 -07002711 mutex_unlock(&qla_fw_lock);
Andrew Vasquez54333832005-11-09 15:49:04 -08002712 return blob;
2713}
2714
2715static void
2716qla2x00_release_firmware(void)
2717{
2718 int idx;
2719
Daniel Walkere1e82b62008-05-12 22:21:10 -07002720 mutex_lock(&qla_fw_lock);
Andrew Vasquez54333832005-11-09 15:49:04 -08002721 for (idx = 0; idx < FW_BLOBS; idx++)
2722 if (qla_fw_blobs[idx].fw)
2723 release_firmware(qla_fw_blobs[idx].fw);
Daniel Walkere1e82b62008-05-12 22:21:10 -07002724 mutex_unlock(&qla_fw_lock);
Andrew Vasquez54333832005-11-09 15:49:04 -08002725}
2726
Seokmann Ju14e660e2007-09-20 14:07:36 -07002727static pci_ers_result_t
2728qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
2729{
2730 switch (state) {
2731 case pci_channel_io_normal:
2732 return PCI_ERS_RESULT_CAN_RECOVER;
2733 case pci_channel_io_frozen:
2734 pci_disable_device(pdev);
2735 return PCI_ERS_RESULT_NEED_RESET;
2736 case pci_channel_io_perm_failure:
2737 qla2x00_remove_one(pdev);
2738 return PCI_ERS_RESULT_DISCONNECT;
2739 }
2740 return PCI_ERS_RESULT_NEED_RESET;
2741}
2742
2743static pci_ers_result_t
2744qla2xxx_pci_mmio_enabled(struct pci_dev *pdev)
2745{
2746 int risc_paused = 0;
2747 uint32_t stat;
2748 unsigned long flags;
2749 scsi_qla_host_t *ha = pci_get_drvdata(pdev);
2750 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
2751 struct device_reg_24xx __iomem *reg24 = &ha->iobase->isp24;
2752
2753 spin_lock_irqsave(&ha->hardware_lock, flags);
2754 if (IS_QLA2100(ha) || IS_QLA2200(ha)){
2755 stat = RD_REG_DWORD(&reg->hccr);
2756 if (stat & HCCR_RISC_PAUSE)
2757 risc_paused = 1;
2758 } else if (IS_QLA23XX(ha)) {
2759 stat = RD_REG_DWORD(&reg->u.isp2300.host_status);
2760 if (stat & HSR_RISC_PAUSED)
2761 risc_paused = 1;
2762 } else if (IS_FWI2_CAPABLE(ha)) {
2763 stat = RD_REG_DWORD(&reg24->host_status);
2764 if (stat & HSRX_RISC_PAUSED)
2765 risc_paused = 1;
2766 }
2767 spin_unlock_irqrestore(&ha->hardware_lock, flags);
2768
2769 if (risc_paused) {
2770 qla_printk(KERN_INFO, ha, "RISC paused -- mmio_enabled, "
2771 "Dumping firmware!\n");
2772 ha->isp_ops->fw_dump(ha, 0);
2773
2774 return PCI_ERS_RESULT_NEED_RESET;
2775 } else
2776 return PCI_ERS_RESULT_RECOVERED;
2777}
2778
2779static pci_ers_result_t
2780qla2xxx_pci_slot_reset(struct pci_dev *pdev)
2781{
2782 pci_ers_result_t ret = PCI_ERS_RESULT_DISCONNECT;
2783 scsi_qla_host_t *ha = pci_get_drvdata(pdev);
Benjamin Herrenschmidt09483912007-12-20 15:28:09 +11002784 int rc;
Seokmann Ju14e660e2007-09-20 14:07:36 -07002785
Benjamin Herrenschmidt09483912007-12-20 15:28:09 +11002786 if (ha->mem_only)
2787 rc = pci_enable_device_mem(pdev);
2788 else
2789 rc = pci_enable_device(pdev);
2790
2791 if (rc) {
Seokmann Ju14e660e2007-09-20 14:07:36 -07002792 qla_printk(KERN_WARNING, ha,
2793 "Can't re-enable PCI device after reset.\n");
2794
2795 return ret;
2796 }
2797 pci_set_master(pdev);
2798
2799 if (ha->isp_ops->pci_config(ha))
2800 return ret;
2801
2802 set_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
2803 if (qla2x00_abort_isp(ha)== QLA_SUCCESS)
2804 ret = PCI_ERS_RESULT_RECOVERED;
2805 clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
2806
2807 return ret;
2808}
2809
2810static void
2811qla2xxx_pci_resume(struct pci_dev *pdev)
2812{
2813 scsi_qla_host_t *ha = pci_get_drvdata(pdev);
2814 int ret;
2815
2816 ret = qla2x00_wait_for_hba_online(ha);
2817 if (ret != QLA_SUCCESS) {
2818 qla_printk(KERN_ERR, ha,
2819 "the device failed to resume I/O "
2820 "from slot/link_reset");
2821 }
2822 pci_cleanup_aer_uncorrect_error_status(pdev);
2823}
2824
2825static struct pci_error_handlers qla2xxx_err_handler = {
2826 .error_detected = qla2xxx_pci_error_detected,
2827 .mmio_enabled = qla2xxx_pci_mmio_enabled,
2828 .slot_reset = qla2xxx_pci_slot_reset,
2829 .resume = qla2xxx_pci_resume,
2830};
2831
Andrew Vasquez54333832005-11-09 15:49:04 -08002832static struct pci_device_id qla2xxx_pci_tbl[] = {
Andrew Vasquez47f5e062006-05-17 15:09:39 -07002833 { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2100) },
2834 { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2200) },
2835 { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2300) },
2836 { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2312) },
2837 { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2322) },
2838 { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP6312) },
2839 { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP6322) },
2840 { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2422) },
2841 { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2432) },
Harihara Kadayam4d4df192008-04-03 13:13:26 -07002842 { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP8432) },
Andrew Vasquez47f5e062006-05-17 15:09:39 -07002843 { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP5422) },
2844 { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP5432) },
Andrew Vasquezc3a2f0d2007-07-19 20:37:34 -07002845 { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2532) },
Andrew Vasquez54333832005-11-09 15:49:04 -08002846 { 0 },
2847};
2848MODULE_DEVICE_TABLE(pci, qla2xxx_pci_tbl);
2849
Andrew Vasquezfca29702005-07-06 10:31:47 -07002850static struct pci_driver qla2xxx_pci_driver = {
Andrew Vasquezcb630672006-05-17 15:09:45 -07002851 .name = QLA2XXX_DRIVER_NAME,
James Bottomley0a21ef12005-12-01 12:51:50 -06002852 .driver = {
2853 .owner = THIS_MODULE,
2854 },
Andrew Vasquezfca29702005-07-06 10:31:47 -07002855 .id_table = qla2xxx_pci_tbl,
Andrew Vasquez7ee61392006-06-23 16:11:22 -07002856 .probe = qla2x00_probe_one,
Adrian Bunk4c993f72008-01-14 00:55:16 -08002857 .remove = qla2x00_remove_one,
Seokmann Ju14e660e2007-09-20 14:07:36 -07002858 .err_handler = &qla2xxx_err_handler,
Andrew Vasquezfca29702005-07-06 10:31:47 -07002859};
2860
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861/**
2862 * qla2x00_module_init - Module initialization.
2863 **/
2864static int __init
2865qla2x00_module_init(void)
2866{
Andrew Vasquezfca29702005-07-06 10:31:47 -07002867 int ret = 0;
2868
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869 /* Allocate cache for SRBs. */
Andrew Vasquez 354d6b22005-04-23 02:47:27 -04002870 srb_cachep = kmem_cache_create("qla2xxx_srbs", sizeof(srb_t), 0,
Paul Mundt20c2df82007-07-20 10:11:58 +09002871 SLAB_HWCACHE_ALIGN, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002872 if (srb_cachep == NULL) {
2873 printk(KERN_ERR
2874 "qla2xxx: Unable to allocate SRB cache...Failing load!\n");
2875 return -ENOMEM;
2876 }
2877
2878 /* Derive version string. */
2879 strcpy(qla2x00_version_str, QLA2XXX_VERSION);
Andrew Vasquez11010fe2006-10-06 09:54:59 -07002880 if (ql2xextended_error_logging)
Andrew Vasquez01819442006-06-23 16:11:10 -07002881 strcat(qla2x00_version_str, "-debug");
2882
Andrew Vasquez1c97a122005-04-21 16:13:36 -04002883 qla2xxx_transport_template =
2884 fc_attach_transport(&qla2xxx_transport_functions);
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07002885 if (!qla2xxx_transport_template) {
2886 kmem_cache_destroy(srb_cachep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887 return -ENODEV;
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07002888 }
2889 qla2xxx_transport_vport_template =
2890 fc_attach_transport(&qla2xxx_transport_vport_functions);
2891 if (!qla2xxx_transport_vport_template) {
2892 kmem_cache_destroy(srb_cachep);
2893 fc_release_transport(qla2xxx_transport_template);
2894 return -ENODEV;
2895 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896
Andrew Vasquezfd9a29f02008-05-12 22:21:08 -07002897 printk(KERN_INFO "QLogic Fibre Channel HBA Driver: %s\n",
2898 qla2x00_version_str);
Andrew Vasquez7ee61392006-06-23 16:11:22 -07002899 ret = pci_register_driver(&qla2xxx_pci_driver);
Andrew Vasquezfca29702005-07-06 10:31:47 -07002900 if (ret) {
2901 kmem_cache_destroy(srb_cachep);
2902 fc_release_transport(qla2xxx_transport_template);
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07002903 fc_release_transport(qla2xxx_transport_vport_template);
Andrew Vasquezfca29702005-07-06 10:31:47 -07002904 }
2905 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906}
2907
2908/**
2909 * qla2x00_module_exit - Module cleanup.
2910 **/
2911static void __exit
2912qla2x00_module_exit(void)
2913{
Andrew Vasquez7ee61392006-06-23 16:11:22 -07002914 pci_unregister_driver(&qla2xxx_pci_driver);
Andrew Vasquez54333832005-11-09 15:49:04 -08002915 qla2x00_release_firmware();
Andrew Vasquez 354d6b22005-04-23 02:47:27 -04002916 kmem_cache_destroy(srb_cachep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002917 fc_release_transport(qla2xxx_transport_template);
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07002918 fc_release_transport(qla2xxx_transport_vport_template);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002919}
2920
2921module_init(qla2x00_module_init);
2922module_exit(qla2x00_module_exit);
2923
2924MODULE_AUTHOR("QLogic Corporation");
2925MODULE_DESCRIPTION("QLogic Fibre Channel HBA Driver");
2926MODULE_LICENSE("GPL");
2927MODULE_VERSION(QLA2XXX_VERSION);
Andrew Vasquezbb8ee492006-10-02 12:00:48 -07002928MODULE_FIRMWARE(FW_FILE_ISP21XX);
2929MODULE_FIRMWARE(FW_FILE_ISP22XX);
2930MODULE_FIRMWARE(FW_FILE_ISP2300);
2931MODULE_FIRMWARE(FW_FILE_ISP2322);
2932MODULE_FIRMWARE(FW_FILE_ISP24XX);
Andrew Vasquez61623fc2008-01-31 12:33:45 -08002933MODULE_FIRMWARE(FW_FILE_ISP25XX);