diff options
Diffstat (limited to 'drivers/scsi/bnx2i/bnx2i_init.c')
-rw-r--r-- | drivers/scsi/bnx2i/bnx2i_init.c | 438 |
1 files changed, 438 insertions, 0 deletions
diff --git a/drivers/scsi/bnx2i/bnx2i_init.c b/drivers/scsi/bnx2i/bnx2i_init.c new file mode 100644 index 000000000000..ae4b2d588fd3 --- /dev/null +++ b/drivers/scsi/bnx2i/bnx2i_init.c | |||
@@ -0,0 +1,438 @@ | |||
1 | /* bnx2i.c: Broadcom NetXtreme II iSCSI driver. | ||
2 | * | ||
3 | * Copyright (c) 2006 - 2009 Broadcom Corporation | ||
4 | * Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved. | ||
5 | * Copyright (c) 2007, 2008 Mike Christie | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation. | ||
10 | * | ||
11 | * Written by: Anil Veerabhadrappa (anilgv@broadcom.com) | ||
12 | */ | ||
13 | |||
14 | #include "bnx2i.h" | ||
15 | |||
16 | static struct list_head adapter_list = LIST_HEAD_INIT(adapter_list); | ||
17 | static u32 adapter_count; | ||
18 | static int bnx2i_reg_device; | ||
19 | |||
20 | #define DRV_MODULE_NAME "bnx2i" | ||
21 | #define DRV_MODULE_VERSION "2.0.1d" | ||
22 | #define DRV_MODULE_RELDATE "Mar 25, 2009" | ||
23 | |||
24 | static char version[] __devinitdata = | ||
25 | "Broadcom NetXtreme II iSCSI Driver " DRV_MODULE_NAME \ | ||
26 | " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; | ||
27 | |||
28 | |||
29 | MODULE_AUTHOR("Anil Veerabhadrappa <anilgv@broadcom.com>"); | ||
30 | MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708/5709 iSCSI Driver"); | ||
31 | MODULE_LICENSE("GPL"); | ||
32 | MODULE_VERSION(DRV_MODULE_VERSION); | ||
33 | |||
34 | static DEFINE_RWLOCK(bnx2i_dev_lock); | ||
35 | |||
36 | unsigned int event_coal_div = 1; | ||
37 | module_param(event_coal_div, int, 0664); | ||
38 | MODULE_PARM_DESC(event_coal_div, "Event Coalescing Divide Factor"); | ||
39 | |||
40 | unsigned int en_tcp_dack = 1; | ||
41 | module_param(en_tcp_dack, int, 0664); | ||
42 | MODULE_PARM_DESC(en_tcp_dack, "Enable TCP Delayed ACK"); | ||
43 | |||
44 | unsigned int error_mask1 = 0x00; | ||
45 | module_param(error_mask1, int, 0664); | ||
46 | MODULE_PARM_DESC(error_mask1, "Config FW iSCSI Error Mask #1"); | ||
47 | |||
48 | unsigned int error_mask2 = 0x00; | ||
49 | module_param(error_mask2, int, 0664); | ||
50 | MODULE_PARM_DESC(error_mask2, "Config FW iSCSI Error Mask #2"); | ||
51 | |||
52 | unsigned int sq_size; | ||
53 | module_param(sq_size, int, 0664); | ||
54 | MODULE_PARM_DESC(sq_size, "Configure SQ size"); | ||
55 | |||
56 | unsigned int rq_size = BNX2I_RQ_WQES_DEFAULT; | ||
57 | module_param(rq_size, int, 0664); | ||
58 | MODULE_PARM_DESC(rq_size, "Configure RQ size"); | ||
59 | |||
60 | u64 iscsi_error_mask = 0x00; | ||
61 | |||
62 | static void bnx2i_unreg_one_device(struct bnx2i_hba *hba) ; | ||
63 | |||
64 | |||
65 | /** | ||
66 | * bnx2i_identify_device - identifies NetXtreme II device type | ||
67 | * @hba: Adapter structure pointer | ||
68 | * | ||
69 | * This function identifies the NX2 device type and sets appropriate | ||
70 | * queue mailbox register access method, 5709 requires driver to | ||
71 | * access MBOX regs using *bin* mode | ||
72 | */ | ||
73 | void bnx2i_identify_device(struct bnx2i_hba *hba) | ||
74 | { | ||
75 | hba->cnic_dev_type = 0; | ||
76 | if ((hba->pci_did == PCI_DEVICE_ID_NX2_5706) || | ||
77 | (hba->pci_did == PCI_DEVICE_ID_NX2_5706S)) | ||
78 | set_bit(BNX2I_NX2_DEV_5706, &hba->cnic_dev_type); | ||
79 | else if ((hba->pci_did == PCI_DEVICE_ID_NX2_5708) || | ||
80 | (hba->pci_did == PCI_DEVICE_ID_NX2_5708S)) | ||
81 | set_bit(BNX2I_NX2_DEV_5708, &hba->cnic_dev_type); | ||
82 | else if ((hba->pci_did == PCI_DEVICE_ID_NX2_5709) || | ||
83 | (hba->pci_did == PCI_DEVICE_ID_NX2_5709S)) { | ||
84 | set_bit(BNX2I_NX2_DEV_5709, &hba->cnic_dev_type); | ||
85 | hba->mail_queue_access = BNX2I_MQ_BIN_MODE; | ||
86 | } else if (hba->pci_did == PCI_DEVICE_ID_NX2_57710 || | ||
87 | hba->pci_did == PCI_DEVICE_ID_NX2_57711) | ||
88 | set_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type); | ||
89 | } | ||
90 | |||
91 | |||
92 | /** | ||
93 | * get_adapter_list_head - returns head of adapter list | ||
94 | */ | ||
95 | struct bnx2i_hba *get_adapter_list_head(void) | ||
96 | { | ||
97 | struct bnx2i_hba *hba = NULL; | ||
98 | struct bnx2i_hba *tmp_hba; | ||
99 | |||
100 | if (!adapter_count) | ||
101 | goto hba_not_found; | ||
102 | |||
103 | read_lock(&bnx2i_dev_lock); | ||
104 | list_for_each_entry(tmp_hba, &adapter_list, link) { | ||
105 | if (tmp_hba->cnic && tmp_hba->cnic->cm_select_dev) { | ||
106 | hba = tmp_hba; | ||
107 | break; | ||
108 | } | ||
109 | } | ||
110 | read_unlock(&bnx2i_dev_lock); | ||
111 | hba_not_found: | ||
112 | return hba; | ||
113 | } | ||
114 | |||
115 | |||
116 | /** | ||
117 | * bnx2i_find_hba_for_cnic - maps cnic device instance to bnx2i adapter instance | ||
118 | * @cnic: pointer to cnic device instance | ||
119 | * | ||
120 | */ | ||
121 | struct bnx2i_hba *bnx2i_find_hba_for_cnic(struct cnic_dev *cnic) | ||
122 | { | ||
123 | struct bnx2i_hba *hba, *temp; | ||
124 | |||
125 | read_lock(&bnx2i_dev_lock); | ||
126 | list_for_each_entry_safe(hba, temp, &adapter_list, link) { | ||
127 | if (hba->cnic == cnic) { | ||
128 | read_unlock(&bnx2i_dev_lock); | ||
129 | return hba; | ||
130 | } | ||
131 | } | ||
132 | read_unlock(&bnx2i_dev_lock); | ||
133 | return NULL; | ||
134 | } | ||
135 | |||
136 | |||
137 | /** | ||
138 | * bnx2i_start - cnic callback to initialize & start adapter instance | ||
139 | * @handle: transparent handle pointing to adapter structure | ||
140 | * | ||
141 | * This function maps adapter structure to pcidev structure and initiates | ||
142 | * firmware handshake to enable/initialize on chip iscsi components | ||
143 | * This bnx2i - cnic interface api callback is issued after following | ||
144 | * 2 conditions are met - | ||
145 | * a) underlying network interface is up (marked by event 'NETDEV_UP' | ||
146 | * from netdev | ||
147 | * b) bnx2i adapter instance is registered | ||
148 | */ | ||
149 | void bnx2i_start(void *handle) | ||
150 | { | ||
151 | #define BNX2I_INIT_POLL_TIME (1000 / HZ) | ||
152 | struct bnx2i_hba *hba = handle; | ||
153 | int i = HZ; | ||
154 | |||
155 | bnx2i_send_fw_iscsi_init_msg(hba); | ||
156 | while (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state) && i--) | ||
157 | msleep(BNX2I_INIT_POLL_TIME); | ||
158 | } | ||
159 | |||
160 | |||
161 | /** | ||
162 | * bnx2i_stop - cnic callback to shutdown adapter instance | ||
163 | * @handle: transparent handle pointing to adapter structure | ||
164 | * | ||
165 | * driver checks if adapter is already in shutdown mode, if not start | ||
166 | * the shutdown process | ||
167 | */ | ||
168 | void bnx2i_stop(void *handle) | ||
169 | { | ||
170 | struct bnx2i_hba *hba = handle; | ||
171 | |||
172 | /* check if cleanup happened in GOING_DOWN context */ | ||
173 | clear_bit(ADAPTER_STATE_UP, &hba->adapter_state); | ||
174 | if (!test_and_clear_bit(ADAPTER_STATE_GOING_DOWN, | ||
175 | &hba->adapter_state)) | ||
176 | iscsi_host_for_each_session(hba->shost, | ||
177 | bnx2i_drop_session); | ||
178 | } | ||
179 | |||
180 | /** | ||
181 | * bnx2i_register_device - register bnx2i adapter instance with the cnic driver | ||
182 | * @hba: Adapter instance to register | ||
183 | * | ||
184 | * registers bnx2i adapter instance with the cnic driver while holding the | ||
185 | * adapter structure lock | ||
186 | */ | ||
187 | void bnx2i_register_device(struct bnx2i_hba *hba) | ||
188 | { | ||
189 | if (test_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state) || | ||
190 | test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) { | ||
191 | return; | ||
192 | } | ||
193 | |||
194 | hba->cnic->register_device(hba->cnic, CNIC_ULP_ISCSI, hba); | ||
195 | |||
196 | spin_lock(&hba->lock); | ||
197 | bnx2i_reg_device++; | ||
198 | spin_unlock(&hba->lock); | ||
199 | |||
200 | set_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic); | ||
201 | } | ||
202 | |||
203 | |||
204 | /** | ||
205 | * bnx2i_reg_dev_all - registers all adapter instances with the cnic driver | ||
206 | * | ||
207 | * registers all bnx2i adapter instances with the cnic driver while holding | ||
208 | * the global resource lock | ||
209 | */ | ||
210 | void bnx2i_reg_dev_all(void) | ||
211 | { | ||
212 | struct bnx2i_hba *hba, *temp; | ||
213 | |||
214 | read_lock(&bnx2i_dev_lock); | ||
215 | list_for_each_entry_safe(hba, temp, &adapter_list, link) | ||
216 | bnx2i_register_device(hba); | ||
217 | read_unlock(&bnx2i_dev_lock); | ||
218 | } | ||
219 | |||
220 | |||
221 | /** | ||
222 | * bnx2i_unreg_one_device - unregister adapter instance with the cnic driver | ||
223 | * @hba: Adapter instance to unregister | ||
224 | * | ||
225 | * registers bnx2i adapter instance with the cnic driver while holding | ||
226 | * the adapter structure lock | ||
227 | */ | ||
228 | static void bnx2i_unreg_one_device(struct bnx2i_hba *hba) | ||
229 | { | ||
230 | if (hba->ofld_conns_active || | ||
231 | !test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic) || | ||
232 | test_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state)) | ||
233 | return; | ||
234 | |||
235 | hba->cnic->unregister_device(hba->cnic, CNIC_ULP_ISCSI); | ||
236 | |||
237 | spin_lock(&hba->lock); | ||
238 | bnx2i_reg_device--; | ||
239 | spin_unlock(&hba->lock); | ||
240 | |||
241 | /* ep_disconnect could come before NETDEV_DOWN, driver won't | ||
242 | * see NETDEV_DOWN as it already unregistered itself. | ||
243 | */ | ||
244 | hba->adapter_state = 0; | ||
245 | clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic); | ||
246 | } | ||
247 | |||
248 | /** | ||
249 | * bnx2i_unreg_dev_all - unregisters all bnx2i instances with the cnic driver | ||
250 | * | ||
251 | * unregisters all bnx2i adapter instances with the cnic driver while holding | ||
252 | * the global resource lock | ||
253 | */ | ||
254 | void bnx2i_unreg_dev_all(void) | ||
255 | { | ||
256 | struct bnx2i_hba *hba, *temp; | ||
257 | |||
258 | read_lock(&bnx2i_dev_lock); | ||
259 | list_for_each_entry_safe(hba, temp, &adapter_list, link) | ||
260 | bnx2i_unreg_one_device(hba); | ||
261 | read_unlock(&bnx2i_dev_lock); | ||
262 | } | ||
263 | |||
264 | |||
265 | /** | ||
266 | * bnx2i_init_one - initialize an adapter instance and allocate memory resources | ||
267 | * @hba: bnx2i adapter instance | ||
268 | * @cnic: cnic device handle | ||
269 | * | ||
270 | * Global resource lock and host adapter lock is held during critical sections | ||
271 | * below. This routine is called from cnic_register_driver() context and | ||
272 | * work horse thread which does majority of device specific initialization | ||
273 | */ | ||
274 | static int bnx2i_init_one(struct bnx2i_hba *hba, struct cnic_dev *cnic) | ||
275 | { | ||
276 | int rc; | ||
277 | |||
278 | read_lock(&bnx2i_dev_lock); | ||
279 | if (bnx2i_reg_device && | ||
280 | !test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) { | ||
281 | rc = cnic->register_device(cnic, CNIC_ULP_ISCSI, hba); | ||
282 | if (rc) /* duplicate registration */ | ||
283 | printk(KERN_ERR "bnx2i- dev reg failed\n"); | ||
284 | |||
285 | spin_lock(&hba->lock); | ||
286 | bnx2i_reg_device++; | ||
287 | hba->age++; | ||
288 | spin_unlock(&hba->lock); | ||
289 | |||
290 | set_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic); | ||
291 | } | ||
292 | read_unlock(&bnx2i_dev_lock); | ||
293 | |||
294 | write_lock(&bnx2i_dev_lock); | ||
295 | list_add_tail(&hba->link, &adapter_list); | ||
296 | adapter_count++; | ||
297 | write_unlock(&bnx2i_dev_lock); | ||
298 | return 0; | ||
299 | } | ||
300 | |||
301 | |||
302 | /** | ||
303 | * bnx2i_ulp_init - initialize an adapter instance | ||
304 | * @dev: cnic device handle | ||
305 | * | ||
306 | * Called from cnic_register_driver() context to initialize all enumerated | ||
307 | * cnic devices. This routine allocate adapter structure and other | ||
308 | * device specific resources. | ||
309 | */ | ||
310 | void bnx2i_ulp_init(struct cnic_dev *dev) | ||
311 | { | ||
312 | struct bnx2i_hba *hba; | ||
313 | |||
314 | /* Allocate a HBA structure for this device */ | ||
315 | hba = bnx2i_alloc_hba(dev); | ||
316 | if (!hba) { | ||
317 | printk(KERN_ERR "bnx2i init: hba initialization failed\n"); | ||
318 | return; | ||
319 | } | ||
320 | |||
321 | /* Get PCI related information and update hba struct members */ | ||
322 | clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic); | ||
323 | if (bnx2i_init_one(hba, dev)) { | ||
324 | printk(KERN_ERR "bnx2i - hba %p init failed\n", hba); | ||
325 | bnx2i_free_hba(hba); | ||
326 | } else | ||
327 | hba->cnic = dev; | ||
328 | } | ||
329 | |||
330 | |||
331 | /** | ||
332 | * bnx2i_ulp_exit - shuts down adapter instance and frees all resources | ||
333 | * @dev: cnic device handle | ||
334 | * | ||
335 | */ | ||
336 | void bnx2i_ulp_exit(struct cnic_dev *dev) | ||
337 | { | ||
338 | struct bnx2i_hba *hba; | ||
339 | |||
340 | hba = bnx2i_find_hba_for_cnic(dev); | ||
341 | if (!hba) { | ||
342 | printk(KERN_INFO "bnx2i_ulp_exit: hba not " | ||
343 | "found, dev 0x%p\n", dev); | ||
344 | return; | ||
345 | } | ||
346 | write_lock(&bnx2i_dev_lock); | ||
347 | list_del_init(&hba->link); | ||
348 | adapter_count--; | ||
349 | |||
350 | if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) { | ||
351 | hba->cnic->unregister_device(hba->cnic, CNIC_ULP_ISCSI); | ||
352 | clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic); | ||
353 | |||
354 | spin_lock(&hba->lock); | ||
355 | bnx2i_reg_device--; | ||
356 | spin_unlock(&hba->lock); | ||
357 | } | ||
358 | write_unlock(&bnx2i_dev_lock); | ||
359 | |||
360 | bnx2i_free_hba(hba); | ||
361 | } | ||
362 | |||
363 | |||
364 | /** | ||
365 | * bnx2i_mod_init - module init entry point | ||
366 | * | ||
367 | * initialize any driver wide global data structures such as endpoint pool, | ||
368 | * tcp port manager/queue, sysfs. finally driver will register itself | ||
369 | * with the cnic module | ||
370 | */ | ||
371 | static int __init bnx2i_mod_init(void) | ||
372 | { | ||
373 | int err; | ||
374 | |||
375 | printk(KERN_INFO "%s", version); | ||
376 | |||
377 | if (!is_power_of_2(sq_size)) | ||
378 | sq_size = roundup_pow_of_two(sq_size); | ||
379 | |||
380 | bnx2i_scsi_xport_template = | ||
381 | iscsi_register_transport(&bnx2i_iscsi_transport); | ||
382 | if (!bnx2i_scsi_xport_template) { | ||
383 | printk(KERN_ERR "Could not register bnx2i transport.\n"); | ||
384 | err = -ENOMEM; | ||
385 | goto out; | ||
386 | } | ||
387 | |||
388 | err = cnic_register_driver(CNIC_ULP_ISCSI, &bnx2i_cnic_cb); | ||
389 | if (err) { | ||
390 | printk(KERN_ERR "Could not register bnx2i cnic driver.\n"); | ||
391 | goto unreg_xport; | ||
392 | } | ||
393 | |||
394 | return 0; | ||
395 | |||
396 | unreg_xport: | ||
397 | iscsi_unregister_transport(&bnx2i_iscsi_transport); | ||
398 | out: | ||
399 | return err; | ||
400 | } | ||
401 | |||
402 | |||
403 | /** | ||
404 | * bnx2i_mod_exit - module cleanup/exit entry point | ||
405 | * | ||
406 | * Global resource lock and host adapter lock is held during critical sections | ||
407 | * in this function. Driver will browse through the adapter list, cleans-up | ||
408 | * each instance, unregisters iscsi transport name and finally driver will | ||
409 | * unregister itself with the cnic module | ||
410 | */ | ||
411 | static void __exit bnx2i_mod_exit(void) | ||
412 | { | ||
413 | struct bnx2i_hba *hba; | ||
414 | |||
415 | write_lock(&bnx2i_dev_lock); | ||
416 | while (!list_empty(&adapter_list)) { | ||
417 | hba = list_entry(adapter_list.next, struct bnx2i_hba, link); | ||
418 | list_del(&hba->link); | ||
419 | adapter_count--; | ||
420 | |||
421 | if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) { | ||
422 | hba->cnic->unregister_device(hba->cnic, CNIC_ULP_ISCSI); | ||
423 | clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic); | ||
424 | bnx2i_reg_device--; | ||
425 | } | ||
426 | |||
427 | write_unlock(&bnx2i_dev_lock); | ||
428 | bnx2i_free_hba(hba); | ||
429 | write_lock(&bnx2i_dev_lock); | ||
430 | } | ||
431 | write_unlock(&bnx2i_dev_lock); | ||
432 | |||
433 | iscsi_unregister_transport(&bnx2i_iscsi_transport); | ||
434 | cnic_unregister_driver(CNIC_ULP_ISCSI); | ||
435 | } | ||
436 | |||
437 | module_init(bnx2i_mod_init); | ||
438 | module_exit(bnx2i_mod_exit); | ||