diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-22 15:55:29 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-22 15:55:29 -0400 |
commit | 424a6f6ef990b7e9f56f6627bfc6c46b493faeb4 (patch) | |
tree | 0028356ed8003495fbbe1f716f359e3c8ebc35b6 /drivers/scsi/qla4xxx | |
parent | 1ab142d499294b844ecc81e8004db4ce029b0b61 (diff) | |
parent | cd8df932d894f3128c884e3ae1b2b484540513db (diff) |
Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
SCSI updates from James Bottomley:
"The update includes the usual assortment of driver updates (lpfc,
qla2xxx, qla4xxx, bfa, bnx2fc, bnx2i, isci, fcoe, hpsa) plus a huge
amount of infrastructure work in the SAS library and transport class
as well as an iSCSI update. There's also a new SCSI based virtio
driver."
* tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6: (177 commits)
[SCSI] qla4xxx: Update driver version to 5.02.00-k15
[SCSI] qla4xxx: trivial cleanup
[SCSI] qla4xxx: Fix sparse warning
[SCSI] qla4xxx: Add support for multiple session per host.
[SCSI] qla4xxx: Export CHAP index as sysfs attribute
[SCSI] scsi_transport: Export CHAP index as sysfs attribute
[SCSI] qla4xxx: Add support to display CHAP list and delete CHAP entry
[SCSI] iscsi_transport: Add support to display CHAP list and delete CHAP entry
[SCSI] pm8001: fix endian issue with code optimization.
[SCSI] pm8001: Fix possible racing condition.
[SCSI] pm8001: Fix bogus interrupt state flag issue.
[SCSI] ipr: update PCI ID definitions for new adapters
[SCSI] qla2xxx: handle default case in qla2x00_request_firmware()
[SCSI] isci: improvements in driver unloading routine
[SCSI] isci: improve phy event warnings
[SCSI] isci: debug, provide state-enum-to-string conversions
[SCSI] scsi_transport_sas: 'enable' phys on reset
[SCSI] libsas: don't recover end devices attached to disabled phys
[SCSI] libsas: fixup target_port_protocols for expanders that don't report sata
[SCSI] libsas: set attached device type and target protocols for local phys
...
Diffstat (limited to 'drivers/scsi/qla4xxx')
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_def.h | 45 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_fw.h | 24 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_glbl.h | 9 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_init.c | 5 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_iocb.c | 92 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_isr.c | 78 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_mbx.c | 23 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_nx.c | 17 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_nx.h | 1 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_os.c | 563 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_version.h | 2 |
11 files changed, 808 insertions, 51 deletions
diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h index bfe68545203f..7f2492e88be7 100644 --- a/drivers/scsi/qla4xxx/ql4_def.h +++ b/drivers/scsi/qla4xxx/ql4_def.h | |||
@@ -150,8 +150,6 @@ | |||
150 | #define QL4_SESS_RECOVERY_TMO 120 /* iSCSI session */ | 150 | #define QL4_SESS_RECOVERY_TMO 120 /* iSCSI session */ |
151 | /* recovery timeout */ | 151 | /* recovery timeout */ |
152 | 152 | ||
153 | #define MSB(x) ((uint8_t)((uint16_t)(x) >> 8)) | ||
154 | #define LSW(x) ((uint16_t)(x)) | ||
155 | #define LSDW(x) ((u32)((u64)(x))) | 153 | #define LSDW(x) ((u32)((u64)(x))) |
156 | #define MSDW(x) ((u32)((((u64)(x)) >> 16) >> 16)) | 154 | #define MSDW(x) ((u32)((((u64)(x)) >> 16) >> 16)) |
157 | 155 | ||
@@ -223,6 +221,15 @@ struct srb { | |||
223 | uint16_t reserved2; | 221 | uint16_t reserved2; |
224 | }; | 222 | }; |
225 | 223 | ||
224 | /* Mailbox request block structure */ | ||
225 | struct mrb { | ||
226 | struct scsi_qla_host *ha; | ||
227 | struct mbox_cmd_iocb *mbox; | ||
228 | uint32_t mbox_cmd; | ||
229 | uint16_t iocb_cnt; /* Number of used iocbs */ | ||
230 | uint32_t pid; | ||
231 | }; | ||
232 | |||
226 | /* | 233 | /* |
227 | * Asynchronous Event Queue structure | 234 | * Asynchronous Event Queue structure |
228 | */ | 235 | */ |
@@ -265,7 +272,7 @@ struct ddb_entry { | |||
265 | * retried */ | 272 | * retried */ |
266 | uint32_t default_time2wait; /* Default Min time between | 273 | uint32_t default_time2wait; /* Default Min time between |
267 | * relogins (+aens) */ | 274 | * relogins (+aens) */ |
268 | 275 | uint16_t chap_tbl_idx; | |
269 | }; | 276 | }; |
270 | 277 | ||
271 | struct qla_ddb_index { | 278 | struct qla_ddb_index { |
@@ -284,6 +291,7 @@ struct ql4_tuple_ddb { | |||
284 | uint16_t options; | 291 | uint16_t options; |
285 | #define DDB_OPT_IPV6 0x0e0e | 292 | #define DDB_OPT_IPV6 0x0e0e |
286 | #define DDB_OPT_IPV4 0x0f0f | 293 | #define DDB_OPT_IPV4 0x0f0f |
294 | uint8_t isid[6]; | ||
287 | }; | 295 | }; |
288 | 296 | ||
289 | /* | 297 | /* |
@@ -303,7 +311,28 @@ struct ql4_tuple_ddb { | |||
303 | #define DF_ISNS_DISCOVERED 2 /* Device was discovered via iSNS */ | 311 | #define DF_ISNS_DISCOVERED 2 /* Device was discovered via iSNS */ |
304 | #define DF_FO_MASKED 3 | 312 | #define DF_FO_MASKED 3 |
305 | 313 | ||
314 | enum qla4_work_type { | ||
315 | QLA4_EVENT_AEN, | ||
316 | QLA4_EVENT_PING_STATUS, | ||
317 | }; | ||
306 | 318 | ||
319 | struct qla4_work_evt { | ||
320 | struct list_head list; | ||
321 | enum qla4_work_type type; | ||
322 | union { | ||
323 | struct { | ||
324 | enum iscsi_host_event_code code; | ||
325 | uint32_t data_size; | ||
326 | uint8_t data[0]; | ||
327 | } aen; | ||
328 | struct { | ||
329 | uint32_t status; | ||
330 | uint32_t pid; | ||
331 | uint32_t data_size; | ||
332 | uint8_t data[0]; | ||
333 | } ping; | ||
334 | } u; | ||
335 | }; | ||
307 | 336 | ||
308 | struct ql82xx_hw_data { | 337 | struct ql82xx_hw_data { |
309 | /* Offsets for flash/nvram access (set to ~0 if not used). */ | 338 | /* Offsets for flash/nvram access (set to ~0 if not used). */ |
@@ -657,6 +686,7 @@ struct scsi_qla_host { | |||
657 | struct dma_pool *chap_dma_pool; | 686 | struct dma_pool *chap_dma_pool; |
658 | uint8_t *chap_list; /* CHAP table cache */ | 687 | uint8_t *chap_list; /* CHAP table cache */ |
659 | struct mutex chap_sem; | 688 | struct mutex chap_sem; |
689 | |||
660 | #define CHAP_DMA_BLOCK_SIZE 512 | 690 | #define CHAP_DMA_BLOCK_SIZE 512 |
661 | struct workqueue_struct *task_wq; | 691 | struct workqueue_struct *task_wq; |
662 | unsigned long ddb_idx_map[MAX_DDB_ENTRIES / BITS_PER_LONG]; | 692 | unsigned long ddb_idx_map[MAX_DDB_ENTRIES / BITS_PER_LONG]; |
@@ -674,6 +704,15 @@ struct scsi_qla_host { | |||
674 | uint16_t sec_ddb_idx; | 704 | uint16_t sec_ddb_idx; |
675 | int is_reset; | 705 | int is_reset; |
676 | uint16_t temperature; | 706 | uint16_t temperature; |
707 | |||
708 | /* event work list */ | ||
709 | struct list_head work_list; | ||
710 | spinlock_t work_lock; | ||
711 | |||
712 | /* mbox iocb */ | ||
713 | #define MAX_MRB 128 | ||
714 | struct mrb *active_mrb_array[MAX_MRB]; | ||
715 | uint32_t mrb_index; | ||
677 | }; | 716 | }; |
678 | 717 | ||
679 | struct ql4_task_data { | 718 | struct ql4_task_data { |
diff --git a/drivers/scsi/qla4xxx/ql4_fw.h b/drivers/scsi/qla4xxx/ql4_fw.h index 7825c141bc1a..210cd1d64475 100644 --- a/drivers/scsi/qla4xxx/ql4_fw.h +++ b/drivers/scsi/qla4xxx/ql4_fw.h | |||
@@ -331,6 +331,10 @@ struct qla_flt_region { | |||
331 | /* Mailbox command definitions */ | 331 | /* Mailbox command definitions */ |
332 | #define MBOX_CMD_ABOUT_FW 0x0009 | 332 | #define MBOX_CMD_ABOUT_FW 0x0009 |
333 | #define MBOX_CMD_PING 0x000B | 333 | #define MBOX_CMD_PING 0x000B |
334 | #define PING_IPV6_PROTOCOL_ENABLE 0x1 | ||
335 | #define PING_IPV6_LINKLOCAL_ADDR 0x4 | ||
336 | #define PING_IPV6_ADDR0 0x8 | ||
337 | #define PING_IPV6_ADDR1 0xC | ||
334 | #define MBOX_CMD_ENABLE_INTRS 0x0010 | 338 | #define MBOX_CMD_ENABLE_INTRS 0x0010 |
335 | #define INTR_DISABLE 0 | 339 | #define INTR_DISABLE 0 |
336 | #define INTR_ENABLE 1 | 340 | #define INTR_ENABLE 1 |
@@ -396,6 +400,10 @@ struct qla_flt_region { | |||
396 | #define FW_ADDSTATE_DHCPv4_LEASE_EXPIRED 0x0008 | 400 | #define FW_ADDSTATE_DHCPv4_LEASE_EXPIRED 0x0008 |
397 | #define FW_ADDSTATE_LINK_UP 0x0010 | 401 | #define FW_ADDSTATE_LINK_UP 0x0010 |
398 | #define FW_ADDSTATE_ISNS_SVC_ENABLED 0x0020 | 402 | #define FW_ADDSTATE_ISNS_SVC_ENABLED 0x0020 |
403 | #define FW_ADDSTATE_LINK_SPEED_10MBPS 0x0100 | ||
404 | #define FW_ADDSTATE_LINK_SPEED_100MBPS 0x0200 | ||
405 | #define FW_ADDSTATE_LINK_SPEED_1GBPS 0x0400 | ||
406 | #define FW_ADDSTATE_LINK_SPEED_10GBPS 0x0800 | ||
399 | 407 | ||
400 | #define MBOX_CMD_GET_DATABASE_ENTRY_DEFAULTS 0x006B | 408 | #define MBOX_CMD_GET_DATABASE_ENTRY_DEFAULTS 0x006B |
401 | #define IPV6_DEFAULT_DDB_ENTRY 0x0001 | 409 | #define IPV6_DEFAULT_DDB_ENTRY 0x0001 |
@@ -918,6 +926,8 @@ struct qla4_header { | |||
918 | #define ET_CMND_T3 0x19 | 926 | #define ET_CMND_T3 0x19 |
919 | #define ET_PASSTHRU0 0x3A | 927 | #define ET_PASSTHRU0 0x3A |
920 | #define ET_PASSTHRU_STATUS 0x3C | 928 | #define ET_PASSTHRU_STATUS 0x3C |
929 | #define ET_MBOX_CMD 0x38 | ||
930 | #define ET_MBOX_STATUS 0x39 | ||
921 | 931 | ||
922 | uint8_t entryStatus; | 932 | uint8_t entryStatus; |
923 | uint8_t systemDefined; | 933 | uint8_t systemDefined; |
@@ -1118,6 +1128,20 @@ struct passthru_status { | |||
1118 | uint8_t res4[16]; /* 30-3F */ | 1128 | uint8_t res4[16]; /* 30-3F */ |
1119 | }; | 1129 | }; |
1120 | 1130 | ||
1131 | struct mbox_cmd_iocb { | ||
1132 | struct qla4_header hdr; /* 00-03 */ | ||
1133 | uint32_t handle; /* 04-07 */ | ||
1134 | uint32_t in_mbox[8]; /* 08-25 */ | ||
1135 | uint32_t res1[6]; /* 26-3F */ | ||
1136 | }; | ||
1137 | |||
1138 | struct mbox_status_iocb { | ||
1139 | struct qla4_header hdr; /* 00-03 */ | ||
1140 | uint32_t handle; /* 04-07 */ | ||
1141 | uint32_t out_mbox[8]; /* 08-25 */ | ||
1142 | uint32_t res1[6]; /* 26-3F */ | ||
1143 | }; | ||
1144 | |||
1121 | /* | 1145 | /* |
1122 | * ISP queue - response queue entry definition. | 1146 | * ISP queue - response queue entry definition. |
1123 | */ | 1147 | */ |
diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h index d0dd4b330206..910536667cf5 100644 --- a/drivers/scsi/qla4xxx/ql4_glbl.h +++ b/drivers/scsi/qla4xxx/ql4_glbl.h | |||
@@ -81,6 +81,8 @@ int qla4xxx_set_flash(struct scsi_qla_host *ha, dma_addr_t dma_addr, | |||
81 | uint32_t offset, uint32_t length, uint32_t options); | 81 | uint32_t offset, uint32_t length, uint32_t options); |
82 | int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, | 82 | int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, |
83 | uint8_t outCount, uint32_t *mbx_cmd, uint32_t *mbx_sts); | 83 | uint8_t outCount, uint32_t *mbx_cmd, uint32_t *mbx_sts); |
84 | int qla4xxx_get_chap_index(struct scsi_qla_host *ha, char *username, | ||
85 | char *password, int bidi, uint16_t *chap_index); | ||
84 | 86 | ||
85 | void qla4xxx_queue_iocb(struct scsi_qla_host *ha); | 87 | void qla4xxx_queue_iocb(struct scsi_qla_host *ha); |
86 | void qla4xxx_complete_iocb(struct scsi_qla_host *ha); | 88 | void qla4xxx_complete_iocb(struct scsi_qla_host *ha); |
@@ -181,6 +183,13 @@ int qla4xxx_flash_ddb_change(struct scsi_qla_host *ha, uint32_t fw_ddb_index, | |||
181 | int qla4xxx_ddb_change(struct scsi_qla_host *ha, uint32_t fw_ddb_index, | 183 | int qla4xxx_ddb_change(struct scsi_qla_host *ha, uint32_t fw_ddb_index, |
182 | struct ddb_entry *ddb_entry, uint32_t state); | 184 | struct ddb_entry *ddb_entry, uint32_t state); |
183 | void qla4xxx_build_ddb_list(struct scsi_qla_host *ha, int is_reset); | 185 | void qla4xxx_build_ddb_list(struct scsi_qla_host *ha, int is_reset); |
186 | int qla4xxx_post_aen_work(struct scsi_qla_host *ha, uint32_t aen_code, | ||
187 | uint32_t data_size, uint8_t *data); | ||
188 | int qla4xxx_ping_iocb(struct scsi_qla_host *ha, uint32_t options, | ||
189 | uint32_t payload_size, uint32_t pid, uint8_t *ipaddr); | ||
190 | int qla4xxx_post_ping_evt_work(struct scsi_qla_host *ha, | ||
191 | uint32_t status, uint32_t pid, | ||
192 | uint32_t data_size, uint8_t *data); | ||
184 | 193 | ||
185 | /* BSG Functions */ | 194 | /* BSG Functions */ |
186 | int qla4xxx_bsg_request(struct bsg_job *bsg_job); | 195 | int qla4xxx_bsg_request(struct bsg_job *bsg_job); |
diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c index 90614f38b55d..90ee5d8fa731 100644 --- a/drivers/scsi/qla4xxx/ql4_init.c +++ b/drivers/scsi/qla4xxx/ql4_init.c | |||
@@ -86,6 +86,7 @@ static void qla4xxx_init_response_q_entries(struct scsi_qla_host *ha) | |||
86 | int qla4xxx_init_rings(struct scsi_qla_host *ha) | 86 | int qla4xxx_init_rings(struct scsi_qla_host *ha) |
87 | { | 87 | { |
88 | unsigned long flags = 0; | 88 | unsigned long flags = 0; |
89 | int i; | ||
89 | 90 | ||
90 | /* Initialize request queue. */ | 91 | /* Initialize request queue. */ |
91 | spin_lock_irqsave(&ha->hardware_lock, flags); | 92 | spin_lock_irqsave(&ha->hardware_lock, flags); |
@@ -125,6 +126,10 @@ int qla4xxx_init_rings(struct scsi_qla_host *ha) | |||
125 | 126 | ||
126 | qla4xxx_init_response_q_entries(ha); | 127 | qla4xxx_init_response_q_entries(ha); |
127 | 128 | ||
129 | /* Initialize mabilbox active array */ | ||
130 | for (i = 0; i < MAX_MRB; i++) | ||
131 | ha->active_mrb_array[i] = NULL; | ||
132 | |||
128 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | 133 | spin_unlock_irqrestore(&ha->hardware_lock, flags); |
129 | 134 | ||
130 | return QLA_SUCCESS; | 135 | return QLA_SUCCESS; |
diff --git a/drivers/scsi/qla4xxx/ql4_iocb.c b/drivers/scsi/qla4xxx/ql4_iocb.c index 410669351906..2a2022a6bb9b 100644 --- a/drivers/scsi/qla4xxx/ql4_iocb.c +++ b/drivers/scsi/qla4xxx/ql4_iocb.c | |||
@@ -445,3 +445,95 @@ queuing_error: | |||
445 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | 445 | spin_unlock_irqrestore(&ha->hardware_lock, flags); |
446 | return ret; | 446 | return ret; |
447 | } | 447 | } |
448 | |||
449 | static struct mrb *qla4xxx_get_new_mrb(struct scsi_qla_host *ha) | ||
450 | { | ||
451 | struct mrb *mrb; | ||
452 | |||
453 | mrb = kzalloc(sizeof(*mrb), GFP_KERNEL); | ||
454 | if (!mrb) | ||
455 | return mrb; | ||
456 | |||
457 | mrb->ha = ha; | ||
458 | return mrb; | ||
459 | } | ||
460 | |||
461 | static int qla4xxx_send_mbox_iocb(struct scsi_qla_host *ha, struct mrb *mrb, | ||
462 | uint32_t *in_mbox) | ||
463 | { | ||
464 | int rval = QLA_SUCCESS; | ||
465 | uint32_t i; | ||
466 | unsigned long flags; | ||
467 | uint32_t index = 0; | ||
468 | |||
469 | /* Acquire hardware specific lock */ | ||
470 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
471 | |||
472 | /* Get pointer to the queue entry for the marker */ | ||
473 | rval = qla4xxx_get_req_pkt(ha, (struct queue_entry **) &(mrb->mbox)); | ||
474 | if (rval != QLA_SUCCESS) | ||
475 | goto exit_mbox_iocb; | ||
476 | |||
477 | index = ha->mrb_index; | ||
478 | /* get valid mrb index*/ | ||
479 | for (i = 0; i < MAX_MRB; i++) { | ||
480 | index++; | ||
481 | if (index == MAX_MRB) | ||
482 | index = 1; | ||
483 | if (ha->active_mrb_array[index] == NULL) { | ||
484 | ha->mrb_index = index; | ||
485 | break; | ||
486 | } | ||
487 | } | ||
488 | |||
489 | mrb->iocb_cnt = 1; | ||
490 | ha->active_mrb_array[index] = mrb; | ||
491 | mrb->mbox->handle = index; | ||
492 | mrb->mbox->hdr.entryType = ET_MBOX_CMD; | ||
493 | mrb->mbox->hdr.entryCount = mrb->iocb_cnt; | ||
494 | memcpy(mrb->mbox->in_mbox, in_mbox, 32); | ||
495 | mrb->mbox_cmd = in_mbox[0]; | ||
496 | wmb(); | ||
497 | |||
498 | ha->isp_ops->queue_iocb(ha); | ||
499 | exit_mbox_iocb: | ||
500 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
501 | return rval; | ||
502 | } | ||
503 | |||
504 | int qla4xxx_ping_iocb(struct scsi_qla_host *ha, uint32_t options, | ||
505 | uint32_t payload_size, uint32_t pid, uint8_t *ipaddr) | ||
506 | { | ||
507 | uint32_t in_mbox[8]; | ||
508 | struct mrb *mrb = NULL; | ||
509 | int rval = QLA_SUCCESS; | ||
510 | |||
511 | memset(in_mbox, 0, sizeof(in_mbox)); | ||
512 | |||
513 | mrb = qla4xxx_get_new_mrb(ha); | ||
514 | if (!mrb) { | ||
515 | DEBUG2(ql4_printk(KERN_WARNING, ha, "%s: fail to get new mrb\n", | ||
516 | __func__)); | ||
517 | rval = QLA_ERROR; | ||
518 | goto exit_ping; | ||
519 | } | ||
520 | |||
521 | in_mbox[0] = MBOX_CMD_PING; | ||
522 | in_mbox[1] = options; | ||
523 | memcpy(&in_mbox[2], &ipaddr[0], 4); | ||
524 | memcpy(&in_mbox[3], &ipaddr[4], 4); | ||
525 | memcpy(&in_mbox[4], &ipaddr[8], 4); | ||
526 | memcpy(&in_mbox[5], &ipaddr[12], 4); | ||
527 | in_mbox[6] = payload_size; | ||
528 | |||
529 | mrb->pid = pid; | ||
530 | rval = qla4xxx_send_mbox_iocb(ha, mrb, in_mbox); | ||
531 | |||
532 | if (rval != QLA_SUCCESS) | ||
533 | goto exit_ping; | ||
534 | |||
535 | return rval; | ||
536 | exit_ping: | ||
537 | kfree(mrb); | ||
538 | return rval; | ||
539 | } | ||
diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c index 95828862eea0..7c9f28b7da72 100644 --- a/drivers/scsi/qla4xxx/ql4_isr.c +++ b/drivers/scsi/qla4xxx/ql4_isr.c | |||
@@ -385,6 +385,71 @@ static void qla4xxx_passthru_status_entry(struct scsi_qla_host *ha, | |||
385 | queue_work(ha->task_wq, &task_data->task_work); | 385 | queue_work(ha->task_wq, &task_data->task_work); |
386 | } | 386 | } |
387 | 387 | ||
388 | static struct mrb *qla4xxx_del_mrb_from_active_array(struct scsi_qla_host *ha, | ||
389 | uint32_t index) | ||
390 | { | ||
391 | struct mrb *mrb = NULL; | ||
392 | |||
393 | /* validate handle and remove from active array */ | ||
394 | if (index >= MAX_MRB) | ||
395 | return mrb; | ||
396 | |||
397 | mrb = ha->active_mrb_array[index]; | ||
398 | ha->active_mrb_array[index] = NULL; | ||
399 | if (!mrb) | ||
400 | return mrb; | ||
401 | |||
402 | /* update counters */ | ||
403 | ha->req_q_count += mrb->iocb_cnt; | ||
404 | ha->iocb_cnt -= mrb->iocb_cnt; | ||
405 | |||
406 | return mrb; | ||
407 | } | ||
408 | |||
409 | static void qla4xxx_mbox_status_entry(struct scsi_qla_host *ha, | ||
410 | struct mbox_status_iocb *mbox_sts_entry) | ||
411 | { | ||
412 | struct mrb *mrb; | ||
413 | uint32_t status; | ||
414 | uint32_t data_size; | ||
415 | |||
416 | mrb = qla4xxx_del_mrb_from_active_array(ha, | ||
417 | le32_to_cpu(mbox_sts_entry->handle)); | ||
418 | |||
419 | if (mrb == NULL) { | ||
420 | ql4_printk(KERN_WARNING, ha, "%s: mrb[%d] is null\n", __func__, | ||
421 | mbox_sts_entry->handle); | ||
422 | return; | ||
423 | } | ||
424 | |||
425 | switch (mrb->mbox_cmd) { | ||
426 | case MBOX_CMD_PING: | ||
427 | DEBUG2(ql4_printk(KERN_INFO, ha, "%s: mbox_cmd = 0x%x, " | ||
428 | "mbox_sts[0] = 0x%x, mbox_sts[6] = 0x%x\n", | ||
429 | __func__, mrb->mbox_cmd, | ||
430 | mbox_sts_entry->out_mbox[0], | ||
431 | mbox_sts_entry->out_mbox[6])); | ||
432 | |||
433 | if (mbox_sts_entry->out_mbox[0] == MBOX_STS_COMMAND_COMPLETE) | ||
434 | status = QLA_SUCCESS; | ||
435 | else | ||
436 | status = QLA_ERROR; | ||
437 | |||
438 | data_size = sizeof(mbox_sts_entry->out_mbox); | ||
439 | |||
440 | qla4xxx_post_ping_evt_work(ha, status, mrb->pid, data_size, | ||
441 | (uint8_t *) mbox_sts_entry->out_mbox); | ||
442 | break; | ||
443 | |||
444 | default: | ||
445 | DEBUG2(ql4_printk(KERN_WARNING, ha, "%s: invalid mbox_cmd = " | ||
446 | "0x%x\n", __func__, mrb->mbox_cmd)); | ||
447 | } | ||
448 | |||
449 | kfree(mrb); | ||
450 | return; | ||
451 | } | ||
452 | |||
388 | /** | 453 | /** |
389 | * qla4xxx_process_response_queue - process response queue completions | 454 | * qla4xxx_process_response_queue - process response queue completions |
390 | * @ha: Pointer to host adapter structure. | 455 | * @ha: Pointer to host adapter structure. |
@@ -461,6 +526,13 @@ void qla4xxx_process_response_queue(struct scsi_qla_host *ha) | |||
461 | "ignoring\n", ha->host_no, __func__)); | 526 | "ignoring\n", ha->host_no, __func__)); |
462 | break; | 527 | break; |
463 | 528 | ||
529 | case ET_MBOX_STATUS: | ||
530 | DEBUG2(ql4_printk(KERN_INFO, ha, | ||
531 | "%s: mbox status IOCB\n", __func__)); | ||
532 | qla4xxx_mbox_status_entry(ha, | ||
533 | (struct mbox_status_iocb *)sts_entry); | ||
534 | break; | ||
535 | |||
464 | default: | 536 | default: |
465 | /* | 537 | /* |
466 | * Invalid entry in response queue, reset RISC | 538 | * Invalid entry in response queue, reset RISC |
@@ -576,6 +648,9 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha, | |||
576 | set_bit(DPC_LINK_CHANGED, &ha->dpc_flags); | 648 | set_bit(DPC_LINK_CHANGED, &ha->dpc_flags); |
577 | 649 | ||
578 | ql4_printk(KERN_INFO, ha, "%s: LINK UP\n", __func__); | 650 | ql4_printk(KERN_INFO, ha, "%s: LINK UP\n", __func__); |
651 | qla4xxx_post_aen_work(ha, ISCSI_EVENT_LINKUP, | ||
652 | sizeof(mbox_sts), | ||
653 | (uint8_t *) mbox_sts); | ||
579 | break; | 654 | break; |
580 | 655 | ||
581 | case MBOX_ASTS_LINK_DOWN: | 656 | case MBOX_ASTS_LINK_DOWN: |
@@ -584,6 +659,9 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha, | |||
584 | set_bit(DPC_LINK_CHANGED, &ha->dpc_flags); | 659 | set_bit(DPC_LINK_CHANGED, &ha->dpc_flags); |
585 | 660 | ||
586 | ql4_printk(KERN_INFO, ha, "%s: LINK DOWN\n", __func__); | 661 | ql4_printk(KERN_INFO, ha, "%s: LINK DOWN\n", __func__); |
662 | qla4xxx_post_aen_work(ha, ISCSI_EVENT_LINKDOWN, | ||
663 | sizeof(mbox_sts), | ||
664 | (uint8_t *) mbox_sts); | ||
587 | break; | 665 | break; |
588 | 666 | ||
589 | case MBOX_ASTS_HEARTBEAT: | 667 | case MBOX_ASTS_HEARTBEAT: |
diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c index e1e66a45e4d0..7ac21dabbf22 100644 --- a/drivers/scsi/qla4xxx/ql4_mbx.c +++ b/drivers/scsi/qla4xxx/ql4_mbx.c | |||
@@ -622,7 +622,7 @@ int qla4xxx_get_firmware_status(struct scsi_qla_host * ha) | |||
622 | return QLA_ERROR; | 622 | return QLA_ERROR; |
623 | } | 623 | } |
624 | 624 | ||
625 | ql4_printk(KERN_INFO, ha, "%ld firmare IOCBs available (%d).\n", | 625 | ql4_printk(KERN_INFO, ha, "%ld firmware IOCBs available (%d).\n", |
626 | ha->host_no, mbox_sts[2]); | 626 | ha->host_no, mbox_sts[2]); |
627 | 627 | ||
628 | return QLA_SUCCESS; | 628 | return QLA_SUCCESS; |
@@ -661,6 +661,8 @@ int qla4xxx_get_fwddb_entry(struct scsi_qla_host *ha, | |||
661 | } | 661 | } |
662 | memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | 662 | memset(&mbox_cmd, 0, sizeof(mbox_cmd)); |
663 | memset(&mbox_sts, 0, sizeof(mbox_sts)); | 663 | memset(&mbox_sts, 0, sizeof(mbox_sts)); |
664 | if (fw_ddb_entry) | ||
665 | memset(fw_ddb_entry, 0, sizeof(struct dev_db_entry)); | ||
664 | 666 | ||
665 | mbox_cmd[0] = MBOX_CMD_GET_DATABASE_ENTRY; | 667 | mbox_cmd[0] = MBOX_CMD_GET_DATABASE_ENTRY; |
666 | mbox_cmd[1] = (uint32_t) fw_ddb_index; | 668 | mbox_cmd[1] = (uint32_t) fw_ddb_index; |
@@ -1424,8 +1426,8 @@ exit_set_chap: | |||
1424 | * match is found. If a match is not found then add the entry in FLASH and | 1426 | * match is found. If a match is not found then add the entry in FLASH and |
1425 | * return the index at which entry is written in the FLASH. | 1427 | * return the index at which entry is written in the FLASH. |
1426 | **/ | 1428 | **/ |
1427 | static int qla4xxx_get_chap_index(struct scsi_qla_host *ha, char *username, | 1429 | int qla4xxx_get_chap_index(struct scsi_qla_host *ha, char *username, |
1428 | char *password, int bidi, uint16_t *chap_index) | 1430 | char *password, int bidi, uint16_t *chap_index) |
1429 | { | 1431 | { |
1430 | int i, rval; | 1432 | int i, rval; |
1431 | int free_index = -1; | 1433 | int free_index = -1; |
@@ -1444,6 +1446,11 @@ static int qla4xxx_get_chap_index(struct scsi_qla_host *ha, char *username, | |||
1444 | return QLA_ERROR; | 1446 | return QLA_ERROR; |
1445 | } | 1447 | } |
1446 | 1448 | ||
1449 | if (!username || !password) { | ||
1450 | ql4_printk(KERN_ERR, ha, "Do not have username and psw\n"); | ||
1451 | return QLA_ERROR; | ||
1452 | } | ||
1453 | |||
1447 | mutex_lock(&ha->chap_sem); | 1454 | mutex_lock(&ha->chap_sem); |
1448 | for (i = 0; i < max_chap_entries; i++) { | 1455 | for (i = 0; i < max_chap_entries; i++) { |
1449 | chap_table = (struct ql4_chap_table *)ha->chap_list + i; | 1456 | chap_table = (struct ql4_chap_table *)ha->chap_list + i; |
@@ -1600,7 +1607,7 @@ int qla4xxx_set_param_ddbentry(struct scsi_qla_host *ha, | |||
1600 | char *ip; | 1607 | char *ip; |
1601 | uint16_t iscsi_opts = 0; | 1608 | uint16_t iscsi_opts = 0; |
1602 | uint32_t options = 0; | 1609 | uint32_t options = 0; |
1603 | uint16_t idx; | 1610 | uint16_t idx, *ptid; |
1604 | 1611 | ||
1605 | fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), | 1612 | fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), |
1606 | &fw_ddb_entry_dma, GFP_KERNEL); | 1613 | &fw_ddb_entry_dma, GFP_KERNEL); |
@@ -1626,6 +1633,14 @@ int qla4xxx_set_param_ddbentry(struct scsi_qla_host *ha, | |||
1626 | goto exit_set_param; | 1633 | goto exit_set_param; |
1627 | } | 1634 | } |
1628 | 1635 | ||
1636 | ptid = (uint16_t *)&fw_ddb_entry->isid[1]; | ||
1637 | *ptid = cpu_to_le16((uint16_t)ddb_entry->sess->target_id); | ||
1638 | |||
1639 | DEBUG2(ql4_printk(KERN_INFO, ha, "ISID [%02x%02x%02x%02x%02x%02x]\n", | ||
1640 | fw_ddb_entry->isid[5], fw_ddb_entry->isid[4], | ||
1641 | fw_ddb_entry->isid[3], fw_ddb_entry->isid[2], | ||
1642 | fw_ddb_entry->isid[1], fw_ddb_entry->isid[0])); | ||
1643 | |||
1629 | iscsi_opts = le16_to_cpu(fw_ddb_entry->iscsi_options); | 1644 | iscsi_opts = le16_to_cpu(fw_ddb_entry->iscsi_options); |
1630 | memset(fw_ddb_entry->iscsi_alias, 0, sizeof(fw_ddb_entry->iscsi_alias)); | 1645 | memset(fw_ddb_entry->iscsi_alias, 0, sizeof(fw_ddb_entry->iscsi_alias)); |
1631 | 1646 | ||
diff --git a/drivers/scsi/qla4xxx/ql4_nx.c b/drivers/scsi/qla4xxx/ql4_nx.c index 65253dfbe962..e1e46b6dac75 100644 --- a/drivers/scsi/qla4xxx/ql4_nx.c +++ b/drivers/scsi/qla4xxx/ql4_nx.c | |||
@@ -841,11 +841,8 @@ qla4_8xxx_rom_lock(struct scsi_qla_host *ha) | |||
841 | done = qla4_8xxx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_LOCK)); | 841 | done = qla4_8xxx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_LOCK)); |
842 | if (done == 1) | 842 | if (done == 1) |
843 | break; | 843 | break; |
844 | if (timeout >= qla4_8xxx_rom_lock_timeout) { | 844 | if (timeout >= qla4_8xxx_rom_lock_timeout) |
845 | ql4_printk(KERN_WARNING, ha, | ||
846 | "%s: Failed to acquire rom lock", __func__); | ||
847 | return -1; | 845 | return -1; |
848 | } | ||
849 | 846 | ||
850 | timeout++; | 847 | timeout++; |
851 | 848 | ||
@@ -996,18 +993,6 @@ qla4_8xxx_pinit_from_rom(struct scsi_qla_host *ha, int verbose) | |||
996 | else | 993 | else |
997 | qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0xffffffff); | 994 | qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0xffffffff); |
998 | 995 | ||
999 | /* reset ms */ | ||
1000 | val = qla4_8xxx_rd_32(ha, QLA82XX_CRB_QDR_NET + 0xe4); | ||
1001 | val |= (1 << 1); | ||
1002 | qla4_8xxx_wr_32(ha, QLA82XX_CRB_QDR_NET + 0xe4, val); | ||
1003 | |||
1004 | msleep(20); | ||
1005 | /* unreset ms */ | ||
1006 | val = qla4_8xxx_rd_32(ha, QLA82XX_CRB_QDR_NET + 0xe4); | ||
1007 | val &= ~(1 << 1); | ||
1008 | qla4_8xxx_wr_32(ha, QLA82XX_CRB_QDR_NET + 0xe4, val); | ||
1009 | msleep(20); | ||
1010 | |||
1011 | qla4_8xxx_rom_unlock(ha); | 996 | qla4_8xxx_rom_unlock(ha); |
1012 | 997 | ||
1013 | /* Read the signature value from the flash. | 998 | /* Read the signature value from the flash. |
diff --git a/drivers/scsi/qla4xxx/ql4_nx.h b/drivers/scsi/qla4xxx/ql4_nx.h index dc45ac923691..dc7500e47b8b 100644 --- a/drivers/scsi/qla4xxx/ql4_nx.h +++ b/drivers/scsi/qla4xxx/ql4_nx.h | |||
@@ -623,6 +623,7 @@ struct crb_addr_pair { | |||
623 | 623 | ||
624 | #define ADDR_ERROR ((unsigned long) 0xffffffff) | 624 | #define ADDR_ERROR ((unsigned long) 0xffffffff) |
625 | #define MAX_CTL_CHECK 1000 | 625 | #define MAX_CTL_CHECK 1000 |
626 | #define QLA82XX_FWERROR_CODE(code) ((code >> 8) & 0x1fffff) | ||
626 | 627 | ||
627 | /*************************************************************************** | 628 | /*************************************************************************** |
628 | * PCI related defines. | 629 | * PCI related defines. |
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index edf503437e96..3d9419460e0c 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c | |||
@@ -32,14 +32,14 @@ static struct kmem_cache *srb_cachep; | |||
32 | /* | 32 | /* |
33 | * Module parameter information and variables | 33 | * Module parameter information and variables |
34 | */ | 34 | */ |
35 | int ql4xdisablesysfsboot = 1; | 35 | static int ql4xdisablesysfsboot = 1; |
36 | module_param(ql4xdisablesysfsboot, int, S_IRUGO | S_IWUSR); | 36 | module_param(ql4xdisablesysfsboot, int, S_IRUGO | S_IWUSR); |
37 | MODULE_PARM_DESC(ql4xdisablesysfsboot, | 37 | MODULE_PARM_DESC(ql4xdisablesysfsboot, |
38 | " Set to disable exporting boot targets to sysfs.\n" | 38 | " Set to disable exporting boot targets to sysfs.\n" |
39 | "\t\t 0 - Export boot targets\n" | 39 | "\t\t 0 - Export boot targets\n" |
40 | "\t\t 1 - Do not export boot targets (Default)"); | 40 | "\t\t 1 - Do not export boot targets (Default)"); |
41 | 41 | ||
42 | int ql4xdontresethba = 0; | 42 | int ql4xdontresethba; |
43 | module_param(ql4xdontresethba, int, S_IRUGO | S_IWUSR); | 43 | module_param(ql4xdontresethba, int, S_IRUGO | S_IWUSR); |
44 | MODULE_PARM_DESC(ql4xdontresethba, | 44 | MODULE_PARM_DESC(ql4xdontresethba, |
45 | " Don't reset the HBA for driver recovery.\n" | 45 | " Don't reset the HBA for driver recovery.\n" |
@@ -71,7 +71,7 @@ MODULE_PARM_DESC(ql4xmaxqdepth, | |||
71 | static int ql4xsess_recovery_tmo = QL4_SESS_RECOVERY_TMO; | 71 | static int ql4xsess_recovery_tmo = QL4_SESS_RECOVERY_TMO; |
72 | module_param(ql4xsess_recovery_tmo, int, S_IRUGO); | 72 | module_param(ql4xsess_recovery_tmo, int, S_IRUGO); |
73 | MODULE_PARM_DESC(ql4xsess_recovery_tmo, | 73 | MODULE_PARM_DESC(ql4xsess_recovery_tmo, |
74 | "Target Session Recovery Timeout.\n" | 74 | " Target Session Recovery Timeout.\n" |
75 | "\t\t Default: 120 sec."); | 75 | "\t\t Default: 120 sec."); |
76 | 76 | ||
77 | static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha); | 77 | static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha); |
@@ -83,6 +83,8 @@ static void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha); | |||
83 | /* | 83 | /* |
84 | * iSCSI template entry points | 84 | * iSCSI template entry points |
85 | */ | 85 | */ |
86 | static int qla4xxx_session_get_param(struct iscsi_cls_session *cls_sess, | ||
87 | enum iscsi_param param, char *buf); | ||
86 | static int qla4xxx_conn_get_param(struct iscsi_cls_conn *conn, | 88 | static int qla4xxx_conn_get_param(struct iscsi_cls_conn *conn, |
87 | enum iscsi_param param, char *buf); | 89 | enum iscsi_param param, char *buf); |
88 | static int qla4xxx_host_get_param(struct Scsi_Host *shost, | 90 | static int qla4xxx_host_get_param(struct Scsi_Host *shost, |
@@ -118,6 +120,13 @@ static void qla4xxx_task_cleanup(struct iscsi_task *); | |||
118 | static void qla4xxx_fail_session(struct iscsi_cls_session *cls_session); | 120 | static void qla4xxx_fail_session(struct iscsi_cls_session *cls_session); |
119 | static void qla4xxx_conn_get_stats(struct iscsi_cls_conn *cls_conn, | 121 | static void qla4xxx_conn_get_stats(struct iscsi_cls_conn *cls_conn, |
120 | struct iscsi_stats *stats); | 122 | struct iscsi_stats *stats); |
123 | static int qla4xxx_send_ping(struct Scsi_Host *shost, uint32_t iface_num, | ||
124 | uint32_t iface_type, uint32_t payload_size, | ||
125 | uint32_t pid, struct sockaddr *dst_addr); | ||
126 | static int qla4xxx_get_chap_list(struct Scsi_Host *shost, uint16_t chap_tbl_idx, | ||
127 | uint32_t *num_entries, char *buf); | ||
128 | static int qla4xxx_delete_chap(struct Scsi_Host *shost, uint16_t chap_tbl_idx); | ||
129 | |||
121 | /* | 130 | /* |
122 | * SCSI host template entry points | 131 | * SCSI host template entry points |
123 | */ | 132 | */ |
@@ -179,7 +188,7 @@ static struct iscsi_transport qla4xxx_iscsi_transport = { | |||
179 | .destroy_conn = qla4xxx_conn_destroy, | 188 | .destroy_conn = qla4xxx_conn_destroy, |
180 | .set_param = iscsi_set_param, | 189 | .set_param = iscsi_set_param, |
181 | .get_conn_param = qla4xxx_conn_get_param, | 190 | .get_conn_param = qla4xxx_conn_get_param, |
182 | .get_session_param = iscsi_session_get_param, | 191 | .get_session_param = qla4xxx_session_get_param, |
183 | .get_ep_param = qla4xxx_get_ep_param, | 192 | .get_ep_param = qla4xxx_get_ep_param, |
184 | .ep_connect = qla4xxx_ep_connect, | 193 | .ep_connect = qla4xxx_ep_connect, |
185 | .ep_poll = qla4xxx_ep_poll, | 194 | .ep_poll = qla4xxx_ep_poll, |
@@ -194,10 +203,93 @@ static struct iscsi_transport qla4xxx_iscsi_transport = { | |||
194 | .set_iface_param = qla4xxx_iface_set_param, | 203 | .set_iface_param = qla4xxx_iface_set_param, |
195 | .get_iface_param = qla4xxx_get_iface_param, | 204 | .get_iface_param = qla4xxx_get_iface_param, |
196 | .bsg_request = qla4xxx_bsg_request, | 205 | .bsg_request = qla4xxx_bsg_request, |
206 | .send_ping = qla4xxx_send_ping, | ||
207 | .get_chap = qla4xxx_get_chap_list, | ||
208 | .delete_chap = qla4xxx_delete_chap, | ||
197 | }; | 209 | }; |
198 | 210 | ||
199 | static struct scsi_transport_template *qla4xxx_scsi_transport; | 211 | static struct scsi_transport_template *qla4xxx_scsi_transport; |
200 | 212 | ||
213 | static int qla4xxx_send_ping(struct Scsi_Host *shost, uint32_t iface_num, | ||
214 | uint32_t iface_type, uint32_t payload_size, | ||
215 | uint32_t pid, struct sockaddr *dst_addr) | ||
216 | { | ||
217 | struct scsi_qla_host *ha = to_qla_host(shost); | ||
218 | struct sockaddr_in *addr; | ||
219 | struct sockaddr_in6 *addr6; | ||
220 | uint32_t options = 0; | ||
221 | uint8_t ipaddr[IPv6_ADDR_LEN]; | ||
222 | int rval; | ||
223 | |||
224 | memset(ipaddr, 0, IPv6_ADDR_LEN); | ||
225 | /* IPv4 to IPv4 */ | ||
226 | if ((iface_type == ISCSI_IFACE_TYPE_IPV4) && | ||
227 | (dst_addr->sa_family == AF_INET)) { | ||
228 | addr = (struct sockaddr_in *)dst_addr; | ||
229 | memcpy(ipaddr, &addr->sin_addr.s_addr, IP_ADDR_LEN); | ||
230 | DEBUG2(ql4_printk(KERN_INFO, ha, "%s: IPv4 Ping src: %pI4 " | ||
231 | "dest: %pI4\n", __func__, | ||
232 | &ha->ip_config.ip_address, ipaddr)); | ||
233 | rval = qla4xxx_ping_iocb(ha, options, payload_size, pid, | ||
234 | ipaddr); | ||
235 | if (rval) | ||
236 | rval = -EINVAL; | ||
237 | } else if ((iface_type == ISCSI_IFACE_TYPE_IPV6) && | ||
238 | (dst_addr->sa_family == AF_INET6)) { | ||
239 | /* IPv6 to IPv6 */ | ||
240 | addr6 = (struct sockaddr_in6 *)dst_addr; | ||
241 | memcpy(ipaddr, &addr6->sin6_addr.in6_u.u6_addr8, IPv6_ADDR_LEN); | ||
242 | |||
243 | options |= PING_IPV6_PROTOCOL_ENABLE; | ||
244 | |||
245 | /* Ping using LinkLocal address */ | ||
246 | if ((iface_num == 0) || (iface_num == 1)) { | ||
247 | DEBUG2(ql4_printk(KERN_INFO, ha, "%s: LinkLocal Ping " | ||
248 | "src: %pI6 dest: %pI6\n", __func__, | ||
249 | &ha->ip_config.ipv6_link_local_addr, | ||
250 | ipaddr)); | ||
251 | options |= PING_IPV6_LINKLOCAL_ADDR; | ||
252 | rval = qla4xxx_ping_iocb(ha, options, payload_size, | ||
253 | pid, ipaddr); | ||
254 | } else { | ||
255 | ql4_printk(KERN_WARNING, ha, "%s: iface num = %d " | ||
256 | "not supported\n", __func__, iface_num); | ||
257 | rval = -ENOSYS; | ||
258 | goto exit_send_ping; | ||
259 | } | ||
260 | |||
261 | /* | ||
262 | * If ping using LinkLocal address fails, try ping using | ||
263 | * IPv6 address | ||
264 | */ | ||
265 | if (rval != QLA_SUCCESS) { | ||
266 | options &= ~PING_IPV6_LINKLOCAL_ADDR; | ||
267 | if (iface_num == 0) { | ||
268 | options |= PING_IPV6_ADDR0; | ||
269 | DEBUG2(ql4_printk(KERN_INFO, ha, "%s: IPv6 " | ||
270 | "Ping src: %pI6 " | ||
271 | "dest: %pI6\n", __func__, | ||
272 | &ha->ip_config.ipv6_addr0, | ||
273 | ipaddr)); | ||
274 | } else if (iface_num == 1) { | ||
275 | options |= PING_IPV6_ADDR1; | ||
276 | DEBUG2(ql4_printk(KERN_INFO, ha, "%s: IPv6 " | ||
277 | "Ping src: %pI6 " | ||
278 | "dest: %pI6\n", __func__, | ||
279 | &ha->ip_config.ipv6_addr1, | ||
280 | ipaddr)); | ||
281 | } | ||
282 | rval = qla4xxx_ping_iocb(ha, options, payload_size, | ||
283 | pid, ipaddr); | ||
284 | if (rval) | ||
285 | rval = -EINVAL; | ||
286 | } | ||
287 | } else | ||
288 | rval = -ENOSYS; | ||
289 | exit_send_ping: | ||
290 | return rval; | ||
291 | } | ||
292 | |||
201 | static umode_t ql4_attr_is_visible(int param_type, int param) | 293 | static umode_t ql4_attr_is_visible(int param_type, int param) |
202 | { | 294 | { |
203 | switch (param_type) { | 295 | switch (param_type) { |
@@ -206,6 +298,8 @@ static umode_t ql4_attr_is_visible(int param_type, int param) | |||
206 | case ISCSI_HOST_PARAM_HWADDRESS: | 298 | case ISCSI_HOST_PARAM_HWADDRESS: |
207 | case ISCSI_HOST_PARAM_IPADDRESS: | 299 | case ISCSI_HOST_PARAM_IPADDRESS: |
208 | case ISCSI_HOST_PARAM_INITIATOR_NAME: | 300 | case ISCSI_HOST_PARAM_INITIATOR_NAME: |
301 | case ISCSI_HOST_PARAM_PORT_STATE: | ||
302 | case ISCSI_HOST_PARAM_PORT_SPEED: | ||
209 | return S_IRUGO; | 303 | return S_IRUGO; |
210 | default: | 304 | default: |
211 | return 0; | 305 | return 0; |
@@ -225,6 +319,12 @@ static umode_t ql4_attr_is_visible(int param_type, int param) | |||
225 | case ISCSI_PARAM_MAX_RECV_DLENGTH: | 319 | case ISCSI_PARAM_MAX_RECV_DLENGTH: |
226 | case ISCSI_PARAM_MAX_XMIT_DLENGTH: | 320 | case ISCSI_PARAM_MAX_XMIT_DLENGTH: |
227 | case ISCSI_PARAM_IFACE_NAME: | 321 | case ISCSI_PARAM_IFACE_NAME: |
322 | case ISCSI_PARAM_CHAP_OUT_IDX: | ||
323 | case ISCSI_PARAM_CHAP_IN_IDX: | ||
324 | case ISCSI_PARAM_USERNAME: | ||
325 | case ISCSI_PARAM_PASSWORD: | ||
326 | case ISCSI_PARAM_USERNAME_IN: | ||
327 | case ISCSI_PARAM_PASSWORD_IN: | ||
228 | return S_IRUGO; | 328 | return S_IRUGO; |
229 | default: | 329 | default: |
230 | return 0; | 330 | return 0; |
@@ -255,6 +355,189 @@ static umode_t ql4_attr_is_visible(int param_type, int param) | |||
255 | return 0; | 355 | return 0; |
256 | } | 356 | } |
257 | 357 | ||
358 | static int qla4xxx_get_chap_list(struct Scsi_Host *shost, uint16_t chap_tbl_idx, | ||
359 | uint32_t *num_entries, char *buf) | ||
360 | { | ||
361 | struct scsi_qla_host *ha = to_qla_host(shost); | ||
362 | struct ql4_chap_table *chap_table; | ||
363 | struct iscsi_chap_rec *chap_rec; | ||
364 | int max_chap_entries = 0; | ||
365 | int valid_chap_entries = 0; | ||
366 | int ret = 0, i; | ||
367 | |||
368 | if (is_qla8022(ha)) | ||
369 | max_chap_entries = (ha->hw.flt_chap_size / 2) / | ||
370 | sizeof(struct ql4_chap_table); | ||
371 | else | ||
372 | max_chap_entries = MAX_CHAP_ENTRIES_40XX; | ||
373 | |||
374 | ql4_printk(KERN_INFO, ha, "%s: num_entries = %d, CHAP idx = %d\n", | ||
375 | __func__, *num_entries, chap_tbl_idx); | ||
376 | |||
377 | if (!buf) { | ||
378 | ret = -ENOMEM; | ||
379 | goto exit_get_chap_list; | ||
380 | } | ||
381 | |||
382 | chap_rec = (struct iscsi_chap_rec *) buf; | ||
383 | mutex_lock(&ha->chap_sem); | ||
384 | for (i = chap_tbl_idx; i < max_chap_entries; i++) { | ||
385 | chap_table = (struct ql4_chap_table *)ha->chap_list + i; | ||
386 | if (chap_table->cookie != | ||
387 | __constant_cpu_to_le16(CHAP_VALID_COOKIE)) | ||
388 | continue; | ||
389 | |||
390 | chap_rec->chap_tbl_idx = i; | ||
391 | strncpy(chap_rec->username, chap_table->name, | ||
392 | ISCSI_CHAP_AUTH_NAME_MAX_LEN); | ||
393 | strncpy(chap_rec->password, chap_table->secret, | ||
394 | QL4_CHAP_MAX_SECRET_LEN); | ||
395 | chap_rec->password_length = chap_table->secret_len; | ||
396 | |||
397 | if (chap_table->flags & BIT_7) /* local */ | ||
398 | chap_rec->chap_type = CHAP_TYPE_OUT; | ||
399 | |||
400 | if (chap_table->flags & BIT_6) /* peer */ | ||
401 | chap_rec->chap_type = CHAP_TYPE_IN; | ||
402 | |||
403 | chap_rec++; | ||
404 | |||
405 | valid_chap_entries++; | ||
406 | if (valid_chap_entries == *num_entries) | ||
407 | break; | ||
408 | else | ||
409 | continue; | ||
410 | } | ||
411 | mutex_unlock(&ha->chap_sem); | ||
412 | |||
413 | exit_get_chap_list: | ||
414 | ql4_printk(KERN_INFO, ha, "%s: Valid CHAP Entries = %d\n", | ||
415 | __func__, valid_chap_entries); | ||
416 | *num_entries = valid_chap_entries; | ||
417 | return ret; | ||
418 | } | ||
419 | |||
420 | static int __qla4xxx_is_chap_active(struct device *dev, void *data) | ||
421 | { | ||
422 | int ret = 0; | ||
423 | uint16_t *chap_tbl_idx = (uint16_t *) data; | ||
424 | struct iscsi_cls_session *cls_session; | ||
425 | struct iscsi_session *sess; | ||
426 | struct ddb_entry *ddb_entry; | ||
427 | |||
428 | if (!iscsi_is_session_dev(dev)) | ||
429 | goto exit_is_chap_active; | ||
430 | |||
431 | cls_session = iscsi_dev_to_session(dev); | ||
432 | sess = cls_session->dd_data; | ||
433 | ddb_entry = sess->dd_data; | ||
434 | |||
435 | if (iscsi_session_chkready(cls_session)) | ||
436 | goto exit_is_chap_active; | ||
437 | |||
438 | if (ddb_entry->chap_tbl_idx == *chap_tbl_idx) | ||
439 | ret = 1; | ||
440 | |||
441 | exit_is_chap_active: | ||
442 | return ret; | ||
443 | } | ||
444 | |||
445 | static int qla4xxx_is_chap_active(struct Scsi_Host *shost, | ||
446 | uint16_t chap_tbl_idx) | ||
447 | { | ||
448 | int ret = 0; | ||
449 | |||
450 | ret = device_for_each_child(&shost->shost_gendev, &chap_tbl_idx, | ||
451 | __qla4xxx_is_chap_active); | ||
452 | |||
453 | return ret; | ||
454 | } | ||
455 | |||
456 | static int qla4xxx_delete_chap(struct Scsi_Host *shost, uint16_t chap_tbl_idx) | ||
457 | { | ||
458 | struct scsi_qla_host *ha = to_qla_host(shost); | ||
459 | struct ql4_chap_table *chap_table; | ||
460 | dma_addr_t chap_dma; | ||
461 | int max_chap_entries = 0; | ||
462 | uint32_t offset = 0; | ||
463 | uint32_t chap_size; | ||
464 | int ret = 0; | ||
465 | |||
466 | chap_table = dma_pool_alloc(ha->chap_dma_pool, GFP_KERNEL, &chap_dma); | ||
467 | if (chap_table == NULL) | ||
468 | return -ENOMEM; | ||
469 | |||
470 | memset(chap_table, 0, sizeof(struct ql4_chap_table)); | ||
471 | |||
472 | if (is_qla8022(ha)) | ||
473 | max_chap_entries = (ha->hw.flt_chap_size / 2) / | ||
474 | sizeof(struct ql4_chap_table); | ||
475 | else | ||
476 | max_chap_entries = MAX_CHAP_ENTRIES_40XX; | ||
477 | |||
478 | if (chap_tbl_idx > max_chap_entries) { | ||
479 | ret = -EINVAL; | ||
480 | goto exit_delete_chap; | ||
481 | } | ||
482 | |||
483 | /* Check if chap index is in use. | ||
484 | * If chap is in use don't delet chap entry */ | ||
485 | ret = qla4xxx_is_chap_active(shost, chap_tbl_idx); | ||
486 | if (ret) { | ||
487 | ql4_printk(KERN_INFO, ha, "CHAP entry %d is in use, cannot " | ||
488 | "delete from flash\n", chap_tbl_idx); | ||
489 | ret = -EBUSY; | ||
490 | goto exit_delete_chap; | ||
491 | } | ||
492 | |||
493 | chap_size = sizeof(struct ql4_chap_table); | ||
494 | if (is_qla40XX(ha)) | ||
495 | offset = FLASH_CHAP_OFFSET | (chap_tbl_idx * chap_size); | ||
496 | else { | ||
497 | offset = FLASH_RAW_ACCESS_ADDR + (ha->hw.flt_region_chap << 2); | ||
498 | /* flt_chap_size is CHAP table size for both ports | ||
499 | * so divide it by 2 to calculate the offset for second port | ||
500 | */ | ||
501 | if (ha->port_num == 1) | ||
502 | offset += (ha->hw.flt_chap_size / 2); | ||
503 | offset += (chap_tbl_idx * chap_size); | ||
504 | } | ||
505 | |||
506 | ret = qla4xxx_get_flash(ha, chap_dma, offset, chap_size); | ||
507 | if (ret != QLA_SUCCESS) { | ||
508 | ret = -EINVAL; | ||
509 | goto exit_delete_chap; | ||
510 | } | ||
511 | |||
512 | DEBUG2(ql4_printk(KERN_INFO, ha, "Chap Cookie: x%x\n", | ||
513 | __le16_to_cpu(chap_table->cookie))); | ||
514 | |||
515 | if (__le16_to_cpu(chap_table->cookie) != CHAP_VALID_COOKIE) { | ||
516 | ql4_printk(KERN_ERR, ha, "No valid chap entry found\n"); | ||
517 | goto exit_delete_chap; | ||
518 | } | ||
519 | |||
520 | chap_table->cookie = __constant_cpu_to_le16(0xFFFF); | ||
521 | |||
522 | offset = FLASH_CHAP_OFFSET | | ||
523 | (chap_tbl_idx * sizeof(struct ql4_chap_table)); | ||
524 | ret = qla4xxx_set_flash(ha, chap_dma, offset, chap_size, | ||
525 | FLASH_OPT_RMW_COMMIT); | ||
526 | if (ret == QLA_SUCCESS && ha->chap_list) { | ||
527 | mutex_lock(&ha->chap_sem); | ||
528 | /* Update ha chap_list cache */ | ||
529 | memcpy((struct ql4_chap_table *)ha->chap_list + chap_tbl_idx, | ||
530 | chap_table, sizeof(struct ql4_chap_table)); | ||
531 | mutex_unlock(&ha->chap_sem); | ||
532 | } | ||
533 | if (ret != QLA_SUCCESS) | ||
534 | ret = -EINVAL; | ||
535 | |||
536 | exit_delete_chap: | ||
537 | dma_pool_free(ha->chap_dma_pool, chap_table, chap_dma); | ||
538 | return ret; | ||
539 | } | ||
540 | |||
258 | static int qla4xxx_get_iface_param(struct iscsi_iface *iface, | 541 | static int qla4xxx_get_iface_param(struct iscsi_iface *iface, |
259 | enum iscsi_param_type param_type, | 542 | enum iscsi_param_type param_type, |
260 | int param, char *buf) | 543 | int param, char *buf) |
@@ -548,6 +831,43 @@ static enum blk_eh_timer_return qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc) | |||
548 | return ret; | 831 | return ret; |
549 | } | 832 | } |
550 | 833 | ||
834 | static void qla4xxx_set_port_speed(struct Scsi_Host *shost) | ||
835 | { | ||
836 | struct scsi_qla_host *ha = to_qla_host(shost); | ||
837 | struct iscsi_cls_host *ihost = shost_priv(shost); | ||
838 | uint32_t speed = ISCSI_PORT_SPEED_UNKNOWN; | ||
839 | |||
840 | qla4xxx_get_firmware_state(ha); | ||
841 | |||
842 | switch (ha->addl_fw_state & 0x0F00) { | ||
843 | case FW_ADDSTATE_LINK_SPEED_10MBPS: | ||
844 | speed = ISCSI_PORT_SPEED_10MBPS; | ||
845 | break; | ||
846 | case FW_ADDSTATE_LINK_SPEED_100MBPS: | ||
847 | speed = ISCSI_PORT_SPEED_100MBPS; | ||
848 | break; | ||
849 | case FW_ADDSTATE_LINK_SPEED_1GBPS: | ||
850 | speed = ISCSI_PORT_SPEED_1GBPS; | ||
851 | break; | ||
852 | case FW_ADDSTATE_LINK_SPEED_10GBPS: | ||
853 | speed = ISCSI_PORT_SPEED_10GBPS; | ||
854 | break; | ||
855 | } | ||
856 | ihost->port_speed = speed; | ||
857 | } | ||
858 | |||
859 | static void qla4xxx_set_port_state(struct Scsi_Host *shost) | ||
860 | { | ||
861 | struct scsi_qla_host *ha = to_qla_host(shost); | ||
862 | struct iscsi_cls_host *ihost = shost_priv(shost); | ||
863 | uint32_t state = ISCSI_PORT_STATE_DOWN; | ||
864 | |||
865 | if (test_bit(AF_LINK_UP, &ha->flags)) | ||
866 | state = ISCSI_PORT_STATE_UP; | ||
867 | |||
868 | ihost->port_state = state; | ||
869 | } | ||
870 | |||
551 | static int qla4xxx_host_get_param(struct Scsi_Host *shost, | 871 | static int qla4xxx_host_get_param(struct Scsi_Host *shost, |
552 | enum iscsi_host_param param, char *buf) | 872 | enum iscsi_host_param param, char *buf) |
553 | { | 873 | { |
@@ -564,6 +884,14 @@ static int qla4xxx_host_get_param(struct Scsi_Host *shost, | |||
564 | case ISCSI_HOST_PARAM_INITIATOR_NAME: | 884 | case ISCSI_HOST_PARAM_INITIATOR_NAME: |
565 | len = sprintf(buf, "%s\n", ha->name_string); | 885 | len = sprintf(buf, "%s\n", ha->name_string); |
566 | break; | 886 | break; |
887 | case ISCSI_HOST_PARAM_PORT_STATE: | ||
888 | qla4xxx_set_port_state(shost); | ||
889 | len = sprintf(buf, "%s\n", iscsi_get_port_state_name(shost)); | ||
890 | break; | ||
891 | case ISCSI_HOST_PARAM_PORT_SPEED: | ||
892 | qla4xxx_set_port_speed(shost); | ||
893 | len = sprintf(buf, "%s\n", iscsi_get_port_speed_name(shost)); | ||
894 | break; | ||
567 | default: | 895 | default: |
568 | return -ENOSYS; | 896 | return -ENOSYS; |
569 | } | 897 | } |
@@ -968,6 +1296,41 @@ exit_init_fw_cb: | |||
968 | return rval; | 1296 | return rval; |
969 | } | 1297 | } |
970 | 1298 | ||
1299 | static int qla4xxx_session_get_param(struct iscsi_cls_session *cls_sess, | ||
1300 | enum iscsi_param param, char *buf) | ||
1301 | { | ||
1302 | struct iscsi_session *sess = cls_sess->dd_data; | ||
1303 | struct ddb_entry *ddb_entry = sess->dd_data; | ||
1304 | struct scsi_qla_host *ha = ddb_entry->ha; | ||
1305 | int rval, len; | ||
1306 | uint16_t idx; | ||
1307 | |||
1308 | switch (param) { | ||
1309 | case ISCSI_PARAM_CHAP_IN_IDX: | ||
1310 | rval = qla4xxx_get_chap_index(ha, sess->username_in, | ||
1311 | sess->password_in, BIDI_CHAP, | ||
1312 | &idx); | ||
1313 | if (rval) | ||
1314 | return -EINVAL; | ||
1315 | |||
1316 | len = sprintf(buf, "%hu\n", idx); | ||
1317 | break; | ||
1318 | case ISCSI_PARAM_CHAP_OUT_IDX: | ||
1319 | rval = qla4xxx_get_chap_index(ha, sess->username, | ||
1320 | sess->password, LOCAL_CHAP, | ||
1321 | &idx); | ||
1322 | if (rval) | ||
1323 | return -EINVAL; | ||
1324 | |||
1325 | len = sprintf(buf, "%hu\n", idx); | ||
1326 | break; | ||
1327 | default: | ||
1328 | return iscsi_session_get_param(cls_sess, param, buf); | ||
1329 | } | ||
1330 | |||
1331 | return len; | ||
1332 | } | ||
1333 | |||
971 | static int qla4xxx_conn_get_param(struct iscsi_cls_conn *cls_conn, | 1334 | static int qla4xxx_conn_get_param(struct iscsi_cls_conn *cls_conn, |
972 | enum iscsi_param param, char *buf) | 1335 | enum iscsi_param param, char *buf) |
973 | { | 1336 | { |
@@ -1506,13 +1869,17 @@ static void qla4xxx_copy_fwddb_param(struct scsi_qla_host *ha, | |||
1506 | { | 1869 | { |
1507 | int buflen = 0; | 1870 | int buflen = 0; |
1508 | struct iscsi_session *sess; | 1871 | struct iscsi_session *sess; |
1872 | struct ddb_entry *ddb_entry; | ||
1509 | struct iscsi_conn *conn; | 1873 | struct iscsi_conn *conn; |
1510 | char ip_addr[DDB_IPADDR_LEN]; | 1874 | char ip_addr[DDB_IPADDR_LEN]; |
1511 | uint16_t options = 0; | 1875 | uint16_t options = 0; |
1512 | 1876 | ||
1513 | sess = cls_sess->dd_data; | 1877 | sess = cls_sess->dd_data; |
1878 | ddb_entry = sess->dd_data; | ||
1514 | conn = cls_conn->dd_data; | 1879 | conn = cls_conn->dd_data; |
1515 | 1880 | ||
1881 | ddb_entry->chap_tbl_idx = le16_to_cpu(fw_ddb_entry->chap_tbl_idx); | ||
1882 | |||
1516 | conn->max_recv_dlength = BYTE_UNITS * | 1883 | conn->max_recv_dlength = BYTE_UNITS * |
1517 | le16_to_cpu(fw_ddb_entry->iscsi_max_rcv_data_seg_len); | 1884 | le16_to_cpu(fw_ddb_entry->iscsi_max_rcv_data_seg_len); |
1518 | 1885 | ||
@@ -1552,6 +1919,8 @@ static void qla4xxx_copy_fwddb_param(struct scsi_qla_host *ha, | |||
1552 | (char *)ha->name_string, buflen); | 1919 | (char *)ha->name_string, buflen); |
1553 | iscsi_set_param(cls_conn, ISCSI_PARAM_PERSISTENT_ADDRESS, | 1920 | iscsi_set_param(cls_conn, ISCSI_PARAM_PERSISTENT_ADDRESS, |
1554 | (char *)ip_addr, buflen); | 1921 | (char *)ip_addr, buflen); |
1922 | iscsi_set_param(cls_conn, ISCSI_PARAM_TARGET_ALIAS, | ||
1923 | (char *)fw_ddb_entry->iscsi_alias, buflen); | ||
1555 | } | 1924 | } |
1556 | 1925 | ||
1557 | void qla4xxx_update_session_conn_fwddb_param(struct scsi_qla_host *ha, | 1926 | void qla4xxx_update_session_conn_fwddb_param(struct scsi_qla_host *ha, |
@@ -1638,6 +2007,7 @@ void qla4xxx_update_session_conn_param(struct scsi_qla_host *ha, | |||
1638 | le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait); | 2007 | le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait); |
1639 | 2008 | ||
1640 | /* Update params */ | 2009 | /* Update params */ |
2010 | ddb_entry->chap_tbl_idx = le16_to_cpu(fw_ddb_entry->chap_tbl_idx); | ||
1641 | conn->max_recv_dlength = BYTE_UNITS * | 2011 | conn->max_recv_dlength = BYTE_UNITS * |
1642 | le16_to_cpu(fw_ddb_entry->iscsi_max_rcv_data_seg_len); | 2012 | le16_to_cpu(fw_ddb_entry->iscsi_max_rcv_data_seg_len); |
1643 | 2013 | ||
@@ -1666,6 +2036,9 @@ void qla4xxx_update_session_conn_param(struct scsi_qla_host *ha, | |||
1666 | memcpy(sess->initiatorname, ha->name_string, | 2036 | memcpy(sess->initiatorname, ha->name_string, |
1667 | min(sizeof(ha->name_string), sizeof(sess->initiatorname))); | 2037 | min(sizeof(ha->name_string), sizeof(sess->initiatorname))); |
1668 | 2038 | ||
2039 | iscsi_set_param(cls_conn, ISCSI_PARAM_TARGET_ALIAS, | ||
2040 | (char *)fw_ddb_entry->iscsi_alias, 0); | ||
2041 | |||
1669 | exit_session_conn_param: | 2042 | exit_session_conn_param: |
1670 | if (fw_ddb_entry) | 2043 | if (fw_ddb_entry) |
1671 | dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), | 2044 | dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), |
@@ -2113,7 +2486,7 @@ void qla4_8xxx_watchdog(struct scsi_qla_host *ha) | |||
2113 | halt_status = qla4_8xxx_rd_32(ha, | 2486 | halt_status = qla4_8xxx_rd_32(ha, |
2114 | QLA82XX_PEG_HALT_STATUS1); | 2487 | QLA82XX_PEG_HALT_STATUS1); |
2115 | 2488 | ||
2116 | if (LSW(MSB(halt_status)) == 0x67) | 2489 | if (QLA82XX_FWERROR_CODE(halt_status) == 0x67) |
2117 | ql4_printk(KERN_ERR, ha, "%s:" | 2490 | ql4_printk(KERN_ERR, ha, "%s:" |
2118 | " Firmware aborted with" | 2491 | " Firmware aborted with" |
2119 | " error code 0x00006700." | 2492 | " error code 0x00006700." |
@@ -2230,6 +2603,10 @@ static void qla4xxx_timer(struct scsi_qla_host *ha) | |||
2230 | } | 2603 | } |
2231 | } | 2604 | } |
2232 | 2605 | ||
2606 | /* Process any deferred work. */ | ||
2607 | if (!list_empty(&ha->work_list)) | ||
2608 | start_dpc++; | ||
2609 | |||
2233 | /* Wakeup the dpc routine for this adapter, if needed. */ | 2610 | /* Wakeup the dpc routine for this adapter, if needed. */ |
2234 | if (start_dpc || | 2611 | if (start_dpc || |
2235 | test_bit(DPC_RESET_HA, &ha->dpc_flags) || | 2612 | test_bit(DPC_RESET_HA, &ha->dpc_flags) || |
@@ -2795,6 +3172,109 @@ void qla4xxx_wake_dpc(struct scsi_qla_host *ha) | |||
2795 | queue_work(ha->dpc_thread, &ha->dpc_work); | 3172 | queue_work(ha->dpc_thread, &ha->dpc_work); |
2796 | } | 3173 | } |
2797 | 3174 | ||
3175 | static struct qla4_work_evt * | ||
3176 | qla4xxx_alloc_work(struct scsi_qla_host *ha, uint32_t data_size, | ||
3177 | enum qla4_work_type type) | ||
3178 | { | ||
3179 | struct qla4_work_evt *e; | ||
3180 | uint32_t size = sizeof(struct qla4_work_evt) + data_size; | ||
3181 | |||
3182 | e = kzalloc(size, GFP_ATOMIC); | ||
3183 | if (!e) | ||
3184 | return NULL; | ||
3185 | |||
3186 | INIT_LIST_HEAD(&e->list); | ||
3187 | e->type = type; | ||
3188 | return e; | ||
3189 | } | ||
3190 | |||
3191 | static void qla4xxx_post_work(struct scsi_qla_host *ha, | ||
3192 | struct qla4_work_evt *e) | ||
3193 | { | ||
3194 | unsigned long flags; | ||
3195 | |||
3196 | spin_lock_irqsave(&ha->work_lock, flags); | ||
3197 | list_add_tail(&e->list, &ha->work_list); | ||
3198 | spin_unlock_irqrestore(&ha->work_lock, flags); | ||
3199 | qla4xxx_wake_dpc(ha); | ||
3200 | } | ||
3201 | |||
3202 | int qla4xxx_post_aen_work(struct scsi_qla_host *ha, | ||
3203 | enum iscsi_host_event_code aen_code, | ||
3204 | uint32_t data_size, uint8_t *data) | ||
3205 | { | ||
3206 | struct qla4_work_evt *e; | ||
3207 | |||
3208 | e = qla4xxx_alloc_work(ha, data_size, QLA4_EVENT_AEN); | ||
3209 | if (!e) | ||
3210 | return QLA_ERROR; | ||
3211 | |||
3212 | e->u.aen.code = aen_code; | ||
3213 | e->u.aen.data_size = data_size; | ||
3214 | memcpy(e->u.aen.data, data, data_size); | ||
3215 | |||
3216 | qla4xxx_post_work(ha, e); | ||
3217 | |||
3218 | return QLA_SUCCESS; | ||
3219 | } | ||
3220 | |||
3221 | int qla4xxx_post_ping_evt_work(struct scsi_qla_host *ha, | ||
3222 | uint32_t status, uint32_t pid, | ||
3223 | uint32_t data_size, uint8_t *data) | ||
3224 | { | ||
3225 | struct qla4_work_evt *e; | ||
3226 | |||
3227 | e = qla4xxx_alloc_work(ha, data_size, QLA4_EVENT_PING_STATUS); | ||
3228 | if (!e) | ||
3229 | return QLA_ERROR; | ||
3230 | |||
3231 | e->u.ping.status = status; | ||
3232 | e->u.ping.pid = pid; | ||
3233 | e->u.ping.data_size = data_size; | ||
3234 | memcpy(e->u.ping.data, data, data_size); | ||
3235 | |||
3236 | qla4xxx_post_work(ha, e); | ||
3237 | |||
3238 | return QLA_SUCCESS; | ||
3239 | } | ||
3240 | |||
3241 | static void qla4xxx_do_work(struct scsi_qla_host *ha) | ||
3242 | { | ||
3243 | struct qla4_work_evt *e, *tmp; | ||
3244 | unsigned long flags; | ||
3245 | LIST_HEAD(work); | ||
3246 | |||
3247 | spin_lock_irqsave(&ha->work_lock, flags); | ||
3248 | list_splice_init(&ha->work_list, &work); | ||
3249 | spin_unlock_irqrestore(&ha->work_lock, flags); | ||
3250 | |||
3251 | list_for_each_entry_safe(e, tmp, &work, list) { | ||
3252 | list_del_init(&e->list); | ||
3253 | |||
3254 | switch (e->type) { | ||
3255 | case QLA4_EVENT_AEN: | ||
3256 | iscsi_post_host_event(ha->host_no, | ||
3257 | &qla4xxx_iscsi_transport, | ||
3258 | e->u.aen.code, | ||
3259 | e->u.aen.data_size, | ||
3260 | e->u.aen.data); | ||
3261 | break; | ||
3262 | case QLA4_EVENT_PING_STATUS: | ||
3263 | iscsi_ping_comp_event(ha->host_no, | ||
3264 | &qla4xxx_iscsi_transport, | ||
3265 | e->u.ping.status, | ||
3266 | e->u.ping.pid, | ||
3267 | e->u.ping.data_size, | ||
3268 | e->u.ping.data); | ||
3269 | break; | ||
3270 | default: | ||
3271 | ql4_printk(KERN_WARNING, ha, "event type: 0x%x not " | ||
3272 | "supported", e->type); | ||
3273 | } | ||
3274 | kfree(e); | ||
3275 | } | ||
3276 | } | ||
3277 | |||
2798 | /** | 3278 | /** |
2799 | * qla4xxx_do_dpc - dpc routine | 3279 | * qla4xxx_do_dpc - dpc routine |
2800 | * @data: in our case pointer to adapter structure | 3280 | * @data: in our case pointer to adapter structure |
@@ -2826,6 +3306,9 @@ static void qla4xxx_do_dpc(struct work_struct *work) | |||
2826 | return; | 3306 | return; |
2827 | } | 3307 | } |
2828 | 3308 | ||
3309 | /* post events to application */ | ||
3310 | qla4xxx_do_work(ha); | ||
3311 | |||
2829 | if (is_qla8022(ha)) { | 3312 | if (is_qla8022(ha)) { |
2830 | if (test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags)) { | 3313 | if (test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags)) { |
2831 | qla4_8xxx_idc_lock(ha); | 3314 | qla4_8xxx_idc_lock(ha); |
@@ -3341,9 +3824,8 @@ static int get_fw_boot_info(struct scsi_qla_host *ha, uint16_t ddb_index[]) | |||
3341 | /* Check Boot Mode */ | 3824 | /* Check Boot Mode */ |
3342 | val = rd_nvram_byte(ha, addr); | 3825 | val = rd_nvram_byte(ha, addr); |
3343 | if (!(val & 0x07)) { | 3826 | if (!(val & 0x07)) { |
3344 | DEBUG2(ql4_printk(KERN_ERR, ha, | 3827 | DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Adapter boot " |
3345 | "%s: Failed Boot options : 0x%x\n", | 3828 | "options : 0x%x\n", __func__, val)); |
3346 | __func__, val)); | ||
3347 | ret = QLA_ERROR; | 3829 | ret = QLA_ERROR; |
3348 | goto exit_boot_info; | 3830 | goto exit_boot_info; |
3349 | } | 3831 | } |
@@ -3388,9 +3870,8 @@ static int get_fw_boot_info(struct scsi_qla_host *ha, uint16_t ddb_index[]) | |||
3388 | } | 3870 | } |
3389 | /* Check Boot Mode */ | 3871 | /* Check Boot Mode */ |
3390 | if (!(buf[1] & 0x07)) { | 3872 | if (!(buf[1] & 0x07)) { |
3391 | DEBUG2(ql4_printk(KERN_INFO, ha, | 3873 | DEBUG2(ql4_printk(KERN_INFO, ha, "Firmware boot options" |
3392 | "Failed: Boot options : 0x%x\n", | 3874 | " : 0x%x\n", buf[1])); |
3393 | buf[1])); | ||
3394 | ret = QLA_ERROR; | 3875 | ret = QLA_ERROR; |
3395 | goto exit_boot_info_free; | 3876 | goto exit_boot_info_free; |
3396 | } | 3877 | } |
@@ -3411,12 +3892,11 @@ static int get_fw_boot_info(struct scsi_qla_host *ha, uint16_t ddb_index[]) | |||
3411 | " target ID %d\n", __func__, ddb_index[0], | 3892 | " target ID %d\n", __func__, ddb_index[0], |
3412 | ddb_index[1])); | 3893 | ddb_index[1])); |
3413 | 3894 | ||
3414 | ha->pri_ddb_idx = ddb_index[0]; | ||
3415 | ha->sec_ddb_idx = ddb_index[1]; | ||
3416 | |||
3417 | exit_boot_info_free: | 3895 | exit_boot_info_free: |
3418 | dma_free_coherent(&ha->pdev->dev, size, buf, buf_dma); | 3896 | dma_free_coherent(&ha->pdev->dev, size, buf, buf_dma); |
3419 | exit_boot_info: | 3897 | exit_boot_info: |
3898 | ha->pri_ddb_idx = ddb_index[0]; | ||
3899 | ha->sec_ddb_idx = ddb_index[1]; | ||
3420 | return ret; | 3900 | return ret; |
3421 | } | 3901 | } |
3422 | 3902 | ||
@@ -3497,8 +3977,8 @@ static int qla4xxx_get_boot_target(struct scsi_qla_host *ha, | |||
3497 | 3977 | ||
3498 | if (qla4xxx_bootdb_by_index(ha, fw_ddb_entry, | 3978 | if (qla4xxx_bootdb_by_index(ha, fw_ddb_entry, |
3499 | fw_ddb_entry_dma, ddb_index)) { | 3979 | fw_ddb_entry_dma, ddb_index)) { |
3500 | DEBUG2(ql4_printk(KERN_ERR, ha, | 3980 | DEBUG2(ql4_printk(KERN_INFO, ha, "%s: No Flash DDB found at " |
3501 | "%s: Flash DDB read Failed\n", __func__)); | 3981 | "index [%d]\n", __func__, ddb_index)); |
3502 | ret = QLA_ERROR; | 3982 | ret = QLA_ERROR; |
3503 | goto exit_boot_target; | 3983 | goto exit_boot_target; |
3504 | } | 3984 | } |
@@ -3576,8 +4056,8 @@ static int qla4xxx_get_boot_info(struct scsi_qla_host *ha) | |||
3576 | ddb_index[1] = 0xffff; | 4056 | ddb_index[1] = 0xffff; |
3577 | ret = get_fw_boot_info(ha, ddb_index); | 4057 | ret = get_fw_boot_info(ha, ddb_index); |
3578 | if (ret != QLA_SUCCESS) { | 4058 | if (ret != QLA_SUCCESS) { |
3579 | DEBUG2(ql4_printk(KERN_ERR, ha, | 4059 | DEBUG2(ql4_printk(KERN_INFO, ha, |
3580 | "%s: Failed to set boot info.\n", __func__)); | 4060 | "%s: No boot target configured.\n", __func__)); |
3581 | return ret; | 4061 | return ret; |
3582 | } | 4062 | } |
3583 | 4063 | ||
@@ -3590,8 +4070,8 @@ static int qla4xxx_get_boot_info(struct scsi_qla_host *ha) | |||
3590 | rval = qla4xxx_get_boot_target(ha, &(ha->boot_tgt.boot_pri_sess), | 4070 | rval = qla4xxx_get_boot_target(ha, &(ha->boot_tgt.boot_pri_sess), |
3591 | ddb_index[0]); | 4071 | ddb_index[0]); |
3592 | if (rval != QLA_SUCCESS) { | 4072 | if (rval != QLA_SUCCESS) { |
3593 | DEBUG2(ql4_printk(KERN_ERR, ha, "%s: Failed to get " | 4073 | DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Primary boot target not " |
3594 | "primary target\n", __func__)); | 4074 | "configured\n", __func__)); |
3595 | } else | 4075 | } else |
3596 | ret = QLA_SUCCESS; | 4076 | ret = QLA_SUCCESS; |
3597 | 4077 | ||
@@ -3602,8 +4082,8 @@ sec_target: | |||
3602 | rval = qla4xxx_get_boot_target(ha, &(ha->boot_tgt.boot_sec_sess), | 4082 | rval = qla4xxx_get_boot_target(ha, &(ha->boot_tgt.boot_sec_sess), |
3603 | ddb_index[1]); | 4083 | ddb_index[1]); |
3604 | if (rval != QLA_SUCCESS) { | 4084 | if (rval != QLA_SUCCESS) { |
3605 | DEBUG2(ql4_printk(KERN_ERR, ha, "%s: Failed to get " | 4085 | DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Secondary boot target not" |
3606 | "secondary target\n", __func__)); | 4086 | " configured\n", __func__)); |
3607 | } else | 4087 | } else |
3608 | ret = QLA_SUCCESS; | 4088 | ret = QLA_SUCCESS; |
3609 | 4089 | ||
@@ -3772,11 +4252,13 @@ static void qla4xxx_convert_param_ddb(struct dev_db_entry *fw_ddb_entry, | |||
3772 | sprintf(tddb->ip_addr, "%pI4", fw_ddb_entry->ip_addr); | 4252 | sprintf(tddb->ip_addr, "%pI4", fw_ddb_entry->ip_addr); |
3773 | 4253 | ||
3774 | tddb->port = le16_to_cpu(fw_ddb_entry->port); | 4254 | tddb->port = le16_to_cpu(fw_ddb_entry->port); |
4255 | memcpy(&tddb->isid[0], &fw_ddb_entry->isid[0], sizeof(tddb->isid)); | ||
3775 | } | 4256 | } |
3776 | 4257 | ||
3777 | static int qla4xxx_compare_tuple_ddb(struct scsi_qla_host *ha, | 4258 | static int qla4xxx_compare_tuple_ddb(struct scsi_qla_host *ha, |
3778 | struct ql4_tuple_ddb *old_tddb, | 4259 | struct ql4_tuple_ddb *old_tddb, |
3779 | struct ql4_tuple_ddb *new_tddb) | 4260 | struct ql4_tuple_ddb *new_tddb, |
4261 | uint8_t is_isid_compare) | ||
3780 | { | 4262 | { |
3781 | if (strcmp(old_tddb->iscsi_name, new_tddb->iscsi_name)) | 4263 | if (strcmp(old_tddb->iscsi_name, new_tddb->iscsi_name)) |
3782 | return QLA_ERROR; | 4264 | return QLA_ERROR; |
@@ -3787,6 +4269,26 @@ static int qla4xxx_compare_tuple_ddb(struct scsi_qla_host *ha, | |||
3787 | if (old_tddb->port != new_tddb->port) | 4269 | if (old_tddb->port != new_tddb->port) |
3788 | return QLA_ERROR; | 4270 | return QLA_ERROR; |
3789 | 4271 | ||
4272 | /* For multi sessions, driver generates the ISID, so do not compare | ||
4273 | * ISID in reset path since it would be a comparision between the | ||
4274 | * driver generated ISID and firmware generated ISID. This could | ||
4275 | * lead to adding duplicated DDBs in the list as driver generated | ||
4276 | * ISID would not match firmware generated ISID. | ||
4277 | */ | ||
4278 | if (is_isid_compare) { | ||
4279 | DEBUG2(ql4_printk(KERN_INFO, ha, "%s: old ISID [%02x%02x%02x" | ||
4280 | "%02x%02x%02x] New ISID [%02x%02x%02x%02x%02x%02x]\n", | ||
4281 | __func__, old_tddb->isid[5], old_tddb->isid[4], | ||
4282 | old_tddb->isid[3], old_tddb->isid[2], old_tddb->isid[1], | ||
4283 | old_tddb->isid[0], new_tddb->isid[5], new_tddb->isid[4], | ||
4284 | new_tddb->isid[3], new_tddb->isid[2], new_tddb->isid[1], | ||
4285 | new_tddb->isid[0])); | ||
4286 | |||
4287 | if (memcmp(&old_tddb->isid[0], &new_tddb->isid[0], | ||
4288 | sizeof(old_tddb->isid))) | ||
4289 | return QLA_ERROR; | ||
4290 | } | ||
4291 | |||
3790 | DEBUG2(ql4_printk(KERN_INFO, ha, | 4292 | DEBUG2(ql4_printk(KERN_INFO, ha, |
3791 | "Match Found, fw[%d,%d,%s,%s], [%d,%d,%s,%s]", | 4293 | "Match Found, fw[%d,%d,%s,%s], [%d,%d,%s,%s]", |
3792 | old_tddb->port, old_tddb->tpgt, old_tddb->ip_addr, | 4294 | old_tddb->port, old_tddb->tpgt, old_tddb->ip_addr, |
@@ -3829,7 +4331,7 @@ static int qla4xxx_is_session_exists(struct scsi_qla_host *ha, | |||
3829 | continue; | 4331 | continue; |
3830 | 4332 | ||
3831 | qla4xxx_get_param_ddb(ddb_entry, tmp_tddb); | 4333 | qla4xxx_get_param_ddb(ddb_entry, tmp_tddb); |
3832 | if (!qla4xxx_compare_tuple_ddb(ha, fw_tddb, tmp_tddb)) { | 4334 | if (!qla4xxx_compare_tuple_ddb(ha, fw_tddb, tmp_tddb, false)) { |
3833 | ret = QLA_SUCCESS; /* found */ | 4335 | ret = QLA_SUCCESS; /* found */ |
3834 | goto exit_check; | 4336 | goto exit_check; |
3835 | } | 4337 | } |
@@ -3872,7 +4374,7 @@ static int qla4xxx_is_flash_ddb_exists(struct scsi_qla_host *ha, | |||
3872 | 4374 | ||
3873 | list_for_each_entry_safe(nt_ddb_idx, nt_ddb_idx_tmp, list_nt, list) { | 4375 | list_for_each_entry_safe(nt_ddb_idx, nt_ddb_idx_tmp, list_nt, list) { |
3874 | qla4xxx_convert_param_ddb(&nt_ddb_idx->fw_ddb, tmp_tddb); | 4376 | qla4xxx_convert_param_ddb(&nt_ddb_idx->fw_ddb, tmp_tddb); |
3875 | if (!qla4xxx_compare_tuple_ddb(ha, fw_tddb, tmp_tddb)) { | 4377 | if (!qla4xxx_compare_tuple_ddb(ha, fw_tddb, tmp_tddb, true)) { |
3876 | ret = QLA_SUCCESS; /* found */ | 4378 | ret = QLA_SUCCESS; /* found */ |
3877 | goto exit_check; | 4379 | goto exit_check; |
3878 | } | 4380 | } |
@@ -4038,6 +4540,10 @@ static void qla4xxx_build_st_list(struct scsi_qla_host *ha, | |||
4038 | if (ret == QLA_ERROR) | 4540 | if (ret == QLA_ERROR) |
4039 | break; | 4541 | break; |
4040 | 4542 | ||
4543 | /* Ignore DDB if invalid state (unassigned) */ | ||
4544 | if (state == DDB_DS_UNASSIGNED) | ||
4545 | goto continue_next_st; | ||
4546 | |||
4041 | /* Check if ST, add to the list_st */ | 4547 | /* Check if ST, add to the list_st */ |
4042 | if (strlen((char *) fw_ddb_entry->iscsi_name) != 0) | 4548 | if (strlen((char *) fw_ddb_entry->iscsi_name) != 0) |
4043 | goto continue_next_st; | 4549 | goto continue_next_st; |
@@ -4397,6 +4903,9 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, | |||
4397 | 4903 | ||
4398 | spin_lock_init(&ha->hardware_lock); | 4904 | spin_lock_init(&ha->hardware_lock); |
4399 | 4905 | ||
4906 | /* Initialize work list */ | ||
4907 | INIT_LIST_HEAD(&ha->work_list); | ||
4908 | |||
4400 | /* Allocate dma buffers */ | 4909 | /* Allocate dma buffers */ |
4401 | if (qla4xxx_mem_alloc(ha)) { | 4910 | if (qla4xxx_mem_alloc(ha)) { |
4402 | ql4_printk(KERN_WARNING, ha, | 4911 | ql4_printk(KERN_WARNING, ha, |
@@ -4524,8 +5033,8 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, | |||
4524 | ha->patch_number, ha->build_number); | 5033 | ha->patch_number, ha->build_number); |
4525 | 5034 | ||
4526 | if (qla4xxx_setup_boot_info(ha)) | 5035 | if (qla4xxx_setup_boot_info(ha)) |
4527 | ql4_printk(KERN_ERR, ha, "%s:ISCSI boot info setup failed\n", | 5036 | ql4_printk(KERN_ERR, ha, |
4528 | __func__); | 5037 | "%s: No iSCSI boot target configured\n", __func__); |
4529 | 5038 | ||
4530 | /* Perform the build ddb list and login to each */ | 5039 | /* Perform the build ddb list and login to each */ |
4531 | qla4xxx_build_ddb_list(ha, INIT_ADAPTER); | 5040 | qla4xxx_build_ddb_list(ha, INIT_ADAPTER); |
diff --git a/drivers/scsi/qla4xxx/ql4_version.h b/drivers/scsi/qla4xxx/ql4_version.h index 133989b3a9f4..ede9af944141 100644 --- a/drivers/scsi/qla4xxx/ql4_version.h +++ b/drivers/scsi/qla4xxx/ql4_version.h | |||
@@ -5,4 +5,4 @@ | |||
5 | * See LICENSE.qla4xxx for copyright and licensing details. | 5 | * See LICENSE.qla4xxx for copyright and licensing details. |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #define QLA4XXX_DRIVER_VERSION "5.02.00-k12" | 8 | #define QLA4XXX_DRIVER_VERSION "5.02.00-k15" |