diff options
author | Mike Christie <michaelc@cs.wisc.edu> | 2011-07-25 14:48:38 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2011-08-27 10:35:58 -0400 |
commit | d00efe3fa87fdf1df3635ba57ef3f14d03bc3ac8 (patch) | |
tree | 7af8d1d78aafc96a14ef8f6a9c1f477c493c0497 /drivers/scsi | |
parent | 56c155b5ca427c9a6312bb0e31865f1c8ab10b2b (diff) |
[SCSI] qla4xxx: add support for set_net_config
Allows user space (iscsiadm) to send down network configuration
parameters for LLD to set private network configuration on the iSCSI
adapters.
Based on patches from Vikas Chaudhary.
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_fw.h | 77 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_glbl.h | 20 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_mbx.c | 119 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_os.c | 282 |
4 files changed, 494 insertions, 4 deletions
diff --git a/drivers/scsi/qla4xxx/ql4_fw.h b/drivers/scsi/qla4xxx/ql4_fw.h index 01082aa77098..21aa1dbaf2c3 100644 --- a/drivers/scsi/qla4xxx/ql4_fw.h +++ b/drivers/scsi/qla4xxx/ql4_fw.h | |||
@@ -434,6 +434,14 @@ struct qla_flt_region { | |||
434 | #define ACB_STATE_VALID 0x05 | 434 | #define ACB_STATE_VALID 0x05 |
435 | #define ACB_STATE_DISABLING 0x06 | 435 | #define ACB_STATE_DISABLING 0x06 |
436 | 436 | ||
437 | /* FLASH offsets */ | ||
438 | #define FLASH_SEGMENT_IFCB 0x04000000 | ||
439 | |||
440 | #define FLASH_OPT_RMW_HOLD 0 | ||
441 | #define FLASH_OPT_RMW_INIT 1 | ||
442 | #define FLASH_OPT_COMMIT 2 | ||
443 | #define FLASH_OPT_RMW_COMMIT 3 | ||
444 | |||
437 | /*************************************************************************/ | 445 | /*************************************************************************/ |
438 | 446 | ||
439 | /* Host Adapter Initialization Control Block (from host) */ | 447 | /* Host Adapter Initialization Control Block (from host) */ |
@@ -473,6 +481,7 @@ struct addr_ctrl_blk { | |||
473 | 481 | ||
474 | uint16_t iscsi_opts; /* 30-31 */ | 482 | uint16_t iscsi_opts; /* 30-31 */ |
475 | uint16_t ipv4_tcp_opts; /* 32-33 */ | 483 | uint16_t ipv4_tcp_opts; /* 32-33 */ |
484 | #define TCPOPT_DHCP_ENABLE 0x0200 | ||
476 | uint16_t ipv4_ip_opts; /* 34-35 */ | 485 | uint16_t ipv4_ip_opts; /* 34-35 */ |
477 | #define IPOPT_IPv4_PROTOCOL_ENABLE 0x8000 | 486 | #define IPOPT_IPv4_PROTOCOL_ENABLE 0x8000 |
478 | 487 | ||
@@ -574,6 +583,74 @@ struct init_fw_ctrl_blk { | |||
574 | /* struct addr_ctrl_blk sec;*/ | 583 | /* struct addr_ctrl_blk sec;*/ |
575 | }; | 584 | }; |
576 | 585 | ||
586 | struct addr_ctrl_blk_def { | ||
587 | uint8_t reserved1[1]; /* 00 */ | ||
588 | uint8_t control; /* 01 */ | ||
589 | uint8_t reserved2[11]; /* 02-0C */ | ||
590 | uint8_t inst_num; /* 0D */ | ||
591 | uint8_t reserved3[34]; /* 0E-2F */ | ||
592 | uint16_t iscsi_opts; /* 30-31 */ | ||
593 | uint16_t ipv4_tcp_opts; /* 32-33 */ | ||
594 | uint16_t ipv4_ip_opts; /* 34-35 */ | ||
595 | uint16_t iscsi_max_pdu_size; /* 36-37 */ | ||
596 | uint8_t ipv4_tos; /* 38 */ | ||
597 | uint8_t ipv4_ttl; /* 39 */ | ||
598 | uint8_t reserved4[2]; /* 3A-3B */ | ||
599 | uint16_t def_timeout; /* 3C-3D */ | ||
600 | uint16_t iscsi_fburst_len; /* 3E-3F */ | ||
601 | uint8_t reserved5[4]; /* 40-43 */ | ||
602 | uint16_t iscsi_max_outstnd_r2t; /* 44-45 */ | ||
603 | uint8_t reserved6[2]; /* 46-47 */ | ||
604 | uint16_t ipv4_port; /* 48-49 */ | ||
605 | uint16_t iscsi_max_burst_len; /* 4A-4B */ | ||
606 | uint8_t reserved7[4]; /* 4C-4F */ | ||
607 | uint8_t ipv4_addr[4]; /* 50-53 */ | ||
608 | uint16_t ipv4_vlan_tag; /* 54-55 */ | ||
609 | uint8_t ipv4_addr_state; /* 56 */ | ||
610 | uint8_t ipv4_cacheid; /* 57 */ | ||
611 | uint8_t reserved8[8]; /* 58-5F */ | ||
612 | uint8_t ipv4_subnet[4]; /* 60-63 */ | ||
613 | uint8_t reserved9[12]; /* 64-6F */ | ||
614 | uint8_t ipv4_gw_addr[4]; /* 70-73 */ | ||
615 | uint8_t reserved10[84]; /* 74-C7 */ | ||
616 | uint8_t abort_timer; /* C8 */ | ||
617 | uint8_t ipv4_tcp_wsf; /* C9 */ | ||
618 | uint8_t reserved11[10]; /* CA-D3 */ | ||
619 | uint8_t ipv4_dhcp_vid_len; /* D4 */ | ||
620 | uint8_t ipv4_dhcp_vid[11]; /* D5-DF */ | ||
621 | uint8_t reserved12[20]; /* E0-F3 */ | ||
622 | uint8_t ipv4_dhcp_alt_cid_len; /* F4 */ | ||
623 | uint8_t ipv4_dhcp_alt_cid[11]; /* F5-FF */ | ||
624 | uint8_t iscsi_name[224]; /* 100-1DF */ | ||
625 | uint8_t reserved13[32]; /* 1E0-1FF */ | ||
626 | uint32_t cookie; /* 200-203 */ | ||
627 | uint16_t ipv6_port; /* 204-205 */ | ||
628 | uint16_t ipv6_opts; /* 206-207 */ | ||
629 | uint16_t ipv6_addtl_opts; /* 208-209 */ | ||
630 | uint16_t ipv6_tcp_opts; /* 20A-20B */ | ||
631 | uint8_t ipv6_tcp_wsf; /* 20C */ | ||
632 | uint16_t ipv6_flow_lbl; /* 20D-20F */ | ||
633 | uint8_t ipv6_dflt_rtr_addr[16]; /* 210-21F */ | ||
634 | uint16_t ipv6_vlan_tag; /* 220-221 */ | ||
635 | uint8_t ipv6_lnk_lcl_addr_state; /* 222 */ | ||
636 | uint8_t ipv6_addr0_state; /* 223 */ | ||
637 | uint8_t ipv6_addr1_state; /* 224 */ | ||
638 | uint8_t ipv6_dflt_rtr_state; /* 225 */ | ||
639 | uint8_t ipv6_traffic_class; /* 226 */ | ||
640 | uint8_t ipv6_hop_limit; /* 227 */ | ||
641 | uint8_t ipv6_if_id[8]; /* 228-22F */ | ||
642 | uint8_t ipv6_addr0[16]; /* 230-23F */ | ||
643 | uint8_t ipv6_addr1[16]; /* 240-24F */ | ||
644 | uint32_t ipv6_nd_reach_time; /* 250-253 */ | ||
645 | uint32_t ipv6_nd_rexmit_timer; /* 254-257 */ | ||
646 | uint32_t ipv6_nd_stale_timeout; /* 258-25B */ | ||
647 | uint8_t ipv6_dup_addr_detect_count; /* 25C */ | ||
648 | uint8_t ipv6_cache_id; /* 25D */ | ||
649 | uint8_t reserved14[18]; /* 25E-26F */ | ||
650 | uint32_t ipv6_gw_advrt_mtu; /* 270-273 */ | ||
651 | uint8_t reserved15[140]; /* 274-2FF */ | ||
652 | }; | ||
653 | |||
577 | /*************************************************************************/ | 654 | /*************************************************************************/ |
578 | 655 | ||
579 | struct dev_db_entry { | 656 | struct dev_db_entry { |
diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h index a53a256c1f8d..786274c48313 100644 --- a/drivers/scsi/qla4xxx/ql4_glbl.h +++ b/drivers/scsi/qla4xxx/ql4_glbl.h | |||
@@ -52,7 +52,17 @@ int qla4xxx_get_fwddb_entry(struct scsi_qla_host *ha, | |||
52 | 52 | ||
53 | int qla4xxx_set_ddb_entry(struct scsi_qla_host * ha, uint16_t fw_ddb_index, | 53 | int qla4xxx_set_ddb_entry(struct scsi_qla_host * ha, uint16_t fw_ddb_index, |
54 | dma_addr_t fw_ddb_entry_dma); | 54 | dma_addr_t fw_ddb_entry_dma); |
55 | 55 | uint8_t qla4xxx_get_ifcb(struct scsi_qla_host *ha, uint32_t *mbox_cmd, | |
56 | uint32_t *mbox_sts, dma_addr_t init_fw_cb_dma); | ||
57 | int qla4xxx_conn_close_sess_logout(struct scsi_qla_host *ha, | ||
58 | uint16_t fw_ddb_index, | ||
59 | uint16_t connection_id, | ||
60 | uint16_t option); | ||
61 | int qla4xxx_disable_acb(struct scsi_qla_host *ha); | ||
62 | int qla4xxx_set_acb(struct scsi_qla_host *ha, uint32_t *mbox_cmd, | ||
63 | uint32_t *mbox_sts, dma_addr_t acb_dma); | ||
64 | int qla4xxx_get_acb(struct scsi_qla_host *ha, uint32_t *mbox_cmd, | ||
65 | uint32_t *mbox_sts, dma_addr_t acb_dma); | ||
56 | void qla4xxx_mark_device_missing(struct scsi_qla_host *ha, | 66 | void qla4xxx_mark_device_missing(struct scsi_qla_host *ha, |
57 | struct ddb_entry *ddb_entry); | 67 | struct ddb_entry *ddb_entry); |
58 | u16 rd_nvram_word(struct scsi_qla_host *ha, int offset); | 68 | u16 rd_nvram_word(struct scsi_qla_host *ha, int offset); |
@@ -75,7 +85,8 @@ void qla4xxx_dump_buffer(void *b, uint32_t size); | |||
75 | int qla4xxx_send_marker_iocb(struct scsi_qla_host *ha, | 85 | int qla4xxx_send_marker_iocb(struct scsi_qla_host *ha, |
76 | struct ddb_entry *ddb_entry, int lun, uint16_t mrkr_mod); | 86 | struct ddb_entry *ddb_entry, int lun, uint16_t mrkr_mod); |
77 | int qla4_is_relogin_allowed(struct scsi_qla_host *ha, uint32_t conn_err); | 87 | int qla4_is_relogin_allowed(struct scsi_qla_host *ha, uint32_t conn_err); |
78 | 88 | int qla4xxx_set_flash(struct scsi_qla_host *ha, dma_addr_t dma_addr, | |
89 | uint32_t offset, uint32_t length, uint32_t options); | ||
79 | int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, | 90 | int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, |
80 | uint8_t outCount, uint32_t *mbx_cmd, uint32_t *mbx_sts); | 91 | uint8_t outCount, uint32_t *mbx_cmd, uint32_t *mbx_sts); |
81 | 92 | ||
@@ -95,6 +106,11 @@ void qla4xxx_wake_dpc(struct scsi_qla_host *ha); | |||
95 | void qla4xxx_get_conn_event_log(struct scsi_qla_host *ha); | 106 | void qla4xxx_get_conn_event_log(struct scsi_qla_host *ha); |
96 | void qla4xxx_mailbox_premature_completion(struct scsi_qla_host *ha); | 107 | void qla4xxx_mailbox_premature_completion(struct scsi_qla_host *ha); |
97 | void qla4xxx_dump_registers(struct scsi_qla_host *ha); | 108 | void qla4xxx_dump_registers(struct scsi_qla_host *ha); |
109 | uint8_t qla4xxx_update_local_ifcb(struct scsi_qla_host *ha, | ||
110 | uint32_t *mbox_cmd, | ||
111 | uint32_t *mbox_sts, | ||
112 | struct addr_ctrl_blk *init_fw_cb, | ||
113 | dma_addr_t init_fw_cb_dma); | ||
98 | 114 | ||
99 | void qla4_8xxx_pci_config(struct scsi_qla_host *); | 115 | void qla4_8xxx_pci_config(struct scsi_qla_host *); |
100 | int qla4_8xxx_iospace_config(struct scsi_qla_host *ha); | 116 | int qla4_8xxx_iospace_config(struct scsi_qla_host *ha); |
diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c index fce8289e9752..559286dcc53c 100644 --- a/drivers/scsi/qla4xxx/ql4_mbx.c +++ b/drivers/scsi/qla4xxx/ql4_mbx.c | |||
@@ -303,7 +303,7 @@ qla4xxx_set_ifcb(struct scsi_qla_host *ha, uint32_t *mbox_cmd, | |||
303 | return QLA_SUCCESS; | 303 | return QLA_SUCCESS; |
304 | } | 304 | } |
305 | 305 | ||
306 | static uint8_t | 306 | uint8_t |
307 | qla4xxx_get_ifcb(struct scsi_qla_host *ha, uint32_t *mbox_cmd, | 307 | qla4xxx_get_ifcb(struct scsi_qla_host *ha, uint32_t *mbox_cmd, |
308 | uint32_t *mbox_sts, dma_addr_t init_fw_cb_dma) | 308 | uint32_t *mbox_sts, dma_addr_t init_fw_cb_dma) |
309 | { | 309 | { |
@@ -363,7 +363,7 @@ qla4xxx_update_local_ip(struct scsi_qla_host *ha, | |||
363 | } | 363 | } |
364 | } | 364 | } |
365 | 365 | ||
366 | static uint8_t | 366 | uint8_t |
367 | qla4xxx_update_local_ifcb(struct scsi_qla_host *ha, | 367 | qla4xxx_update_local_ifcb(struct scsi_qla_host *ha, |
368 | uint32_t *mbox_cmd, | 368 | uint32_t *mbox_cmd, |
369 | uint32_t *mbox_sts, | 369 | uint32_t *mbox_sts, |
@@ -1207,3 +1207,118 @@ exit_send_tgts_no_free: | |||
1207 | return ret_val; | 1207 | return ret_val; |
1208 | } | 1208 | } |
1209 | 1209 | ||
1210 | int qla4xxx_set_flash(struct scsi_qla_host *ha, dma_addr_t dma_addr, | ||
1211 | uint32_t offset, uint32_t length, uint32_t options) | ||
1212 | { | ||
1213 | uint32_t mbox_cmd[MBOX_REG_COUNT]; | ||
1214 | uint32_t mbox_sts[MBOX_REG_COUNT]; | ||
1215 | int status = QLA_SUCCESS; | ||
1216 | |||
1217 | memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | ||
1218 | memset(&mbox_sts, 0, sizeof(mbox_sts)); | ||
1219 | |||
1220 | mbox_cmd[0] = MBOX_CMD_WRITE_FLASH; | ||
1221 | mbox_cmd[1] = LSDW(dma_addr); | ||
1222 | mbox_cmd[2] = MSDW(dma_addr); | ||
1223 | mbox_cmd[3] = offset; | ||
1224 | mbox_cmd[4] = length; | ||
1225 | mbox_cmd[5] = options; | ||
1226 | |||
1227 | status = qla4xxx_mailbox_command(ha, 6, 2, &mbox_cmd[0], &mbox_sts[0]); | ||
1228 | if (status != QLA_SUCCESS) { | ||
1229 | DEBUG2(ql4_printk(KERN_WARNING, ha, "%s: MBOX_CMD_WRITE_FLASH " | ||
1230 | "failed w/ status %04X, mbx1 %04X\n", | ||
1231 | __func__, mbox_sts[0], mbox_sts[1])); | ||
1232 | } | ||
1233 | return status; | ||
1234 | } | ||
1235 | |||
1236 | int qla4xxx_conn_close_sess_logout(struct scsi_qla_host *ha, | ||
1237 | uint16_t fw_ddb_index, | ||
1238 | uint16_t connection_id, | ||
1239 | uint16_t option) | ||
1240 | { | ||
1241 | uint32_t mbox_cmd[MBOX_REG_COUNT]; | ||
1242 | uint32_t mbox_sts[MBOX_REG_COUNT]; | ||
1243 | int status = QLA_SUCCESS; | ||
1244 | |||
1245 | memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | ||
1246 | memset(&mbox_sts, 0, sizeof(mbox_sts)); | ||
1247 | |||
1248 | mbox_cmd[0] = MBOX_CMD_CONN_CLOSE_SESS_LOGOUT; | ||
1249 | mbox_cmd[1] = fw_ddb_index; | ||
1250 | mbox_cmd[2] = connection_id; | ||
1251 | mbox_cmd[3] = option; | ||
1252 | |||
1253 | status = qla4xxx_mailbox_command(ha, 4, 2, &mbox_cmd[0], &mbox_sts[0]); | ||
1254 | if (status != QLA_SUCCESS) { | ||
1255 | DEBUG2(ql4_printk(KERN_WARNING, ha, "%s: MBOX_CMD_CONN_CLOSE " | ||
1256 | "option %04x failed w/ status %04X %04X\n", | ||
1257 | __func__, option, mbox_sts[0], mbox_sts[1])); | ||
1258 | } | ||
1259 | return status; | ||
1260 | } | ||
1261 | |||
1262 | int qla4xxx_disable_acb(struct scsi_qla_host *ha) | ||
1263 | { | ||
1264 | uint32_t mbox_cmd[MBOX_REG_COUNT]; | ||
1265 | uint32_t mbox_sts[MBOX_REG_COUNT]; | ||
1266 | int status = QLA_SUCCESS; | ||
1267 | |||
1268 | memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | ||
1269 | memset(&mbox_sts, 0, sizeof(mbox_sts)); | ||
1270 | |||
1271 | mbox_cmd[0] = MBOX_CMD_DISABLE_ACB; | ||
1272 | |||
1273 | status = qla4xxx_mailbox_command(ha, 8, 5, &mbox_cmd[0], &mbox_sts[0]); | ||
1274 | if (status != QLA_SUCCESS) { | ||
1275 | DEBUG2(ql4_printk(KERN_WARNING, ha, "%s: MBOX_CMD_DISABLE_ACB " | ||
1276 | "failed w/ status %04X %04X %04X", __func__, | ||
1277 | mbox_sts[0], mbox_sts[1], mbox_sts[2])); | ||
1278 | } | ||
1279 | return status; | ||
1280 | } | ||
1281 | |||
1282 | int qla4xxx_get_acb(struct scsi_qla_host *ha, uint32_t *mbox_cmd, | ||
1283 | uint32_t *mbox_sts, dma_addr_t acb_dma) | ||
1284 | { | ||
1285 | int status = QLA_SUCCESS; | ||
1286 | |||
1287 | memset(mbox_cmd, 0, sizeof(mbox_cmd[0]) * MBOX_REG_COUNT); | ||
1288 | memset(mbox_sts, 0, sizeof(mbox_sts[0]) * MBOX_REG_COUNT); | ||
1289 | mbox_cmd[0] = MBOX_CMD_GET_ACB; | ||
1290 | mbox_cmd[1] = 0; /* Primary ACB */ | ||
1291 | mbox_cmd[2] = LSDW(acb_dma); | ||
1292 | mbox_cmd[3] = MSDW(acb_dma); | ||
1293 | mbox_cmd[4] = sizeof(struct addr_ctrl_blk); | ||
1294 | |||
1295 | status = qla4xxx_mailbox_command(ha, 5, 5, &mbox_cmd[0], &mbox_sts[0]); | ||
1296 | if (status != QLA_SUCCESS) { | ||
1297 | DEBUG2(ql4_printk(KERN_WARNING, ha, "%s: MBOX_CMD_GET_ACB " | ||
1298 | "failed w/ status %04X\n", __func__, | ||
1299 | mbox_sts[0])); | ||
1300 | } | ||
1301 | return status; | ||
1302 | } | ||
1303 | |||
1304 | int qla4xxx_set_acb(struct scsi_qla_host *ha, uint32_t *mbox_cmd, | ||
1305 | uint32_t *mbox_sts, dma_addr_t acb_dma) | ||
1306 | { | ||
1307 | int status = QLA_SUCCESS; | ||
1308 | |||
1309 | memset(mbox_cmd, 0, sizeof(mbox_cmd[0]) * MBOX_REG_COUNT); | ||
1310 | memset(mbox_sts, 0, sizeof(mbox_sts[0]) * MBOX_REG_COUNT); | ||
1311 | mbox_cmd[0] = MBOX_CMD_SET_ACB; | ||
1312 | mbox_cmd[1] = 0; /* Primary ACB */ | ||
1313 | mbox_cmd[2] = LSDW(acb_dma); | ||
1314 | mbox_cmd[3] = MSDW(acb_dma); | ||
1315 | mbox_cmd[4] = sizeof(struct addr_ctrl_blk); | ||
1316 | |||
1317 | status = qla4xxx_mailbox_command(ha, 5, 5, &mbox_cmd[0], &mbox_sts[0]); | ||
1318 | if (status != QLA_SUCCESS) { | ||
1319 | DEBUG2(ql4_printk(KERN_WARNING, ha, "%s: MBOX_CMD_SET_ACB " | ||
1320 | "failed w/ status %04X\n", __func__, | ||
1321 | mbox_sts[0])); | ||
1322 | } | ||
1323 | return status; | ||
1324 | } | ||
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index f2364ec59f03..586f12f17c33 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c | |||
@@ -80,6 +80,8 @@ static int qla4xxx_sess_get_param(struct iscsi_cls_session *sess, | |||
80 | enum iscsi_param param, char *buf); | 80 | enum iscsi_param param, char *buf); |
81 | static int qla4xxx_host_get_param(struct Scsi_Host *shost, | 81 | static int qla4xxx_host_get_param(struct Scsi_Host *shost, |
82 | enum iscsi_host_param param, char *buf); | 82 | enum iscsi_host_param param, char *buf); |
83 | static int qla4xxx_iface_set_param(struct Scsi_Host *shost, char *data, | ||
84 | int count); | ||
83 | static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session); | 85 | static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session); |
84 | static enum blk_eh_timer_return qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc); | 86 | static enum blk_eh_timer_return qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc); |
85 | 87 | ||
@@ -142,6 +144,7 @@ static struct iscsi_transport qla4xxx_iscsi_transport = { | |||
142 | .get_conn_param = qla4xxx_conn_get_param, | 144 | .get_conn_param = qla4xxx_conn_get_param, |
143 | .get_session_param = qla4xxx_sess_get_param, | 145 | .get_session_param = qla4xxx_sess_get_param, |
144 | .get_host_param = qla4xxx_host_get_param, | 146 | .get_host_param = qla4xxx_host_get_param, |
147 | .set_iface_param = qla4xxx_iface_set_param, | ||
145 | .session_recovery_timedout = qla4xxx_recovery_timedout, | 148 | .session_recovery_timedout = qla4xxx_recovery_timedout, |
146 | }; | 149 | }; |
147 | 150 | ||
@@ -202,6 +205,285 @@ static int qla4xxx_host_get_param(struct Scsi_Host *shost, | |||
202 | return len; | 205 | return len; |
203 | } | 206 | } |
204 | 207 | ||
208 | static void qla4xxx_set_ipv6(struct scsi_qla_host *ha, | ||
209 | struct iscsi_iface_param_info *iface_param, | ||
210 | struct addr_ctrl_blk *init_fw_cb) | ||
211 | { | ||
212 | /* | ||
213 | * iface_num 0 is valid for IPv6 Addr, linklocal, router, autocfg. | ||
214 | * iface_num 1 is valid only for IPv6 Addr. | ||
215 | */ | ||
216 | switch (iface_param->param) { | ||
217 | case ISCSI_NET_PARAM_IPV6_ADDR: | ||
218 | if (iface_param->iface_num & 0x1) | ||
219 | /* IPv6 Addr 1 */ | ||
220 | memcpy(init_fw_cb->ipv6_addr1, iface_param->value, | ||
221 | sizeof(init_fw_cb->ipv6_addr1)); | ||
222 | else | ||
223 | /* IPv6 Addr 0 */ | ||
224 | memcpy(init_fw_cb->ipv6_addr0, iface_param->value, | ||
225 | sizeof(init_fw_cb->ipv6_addr0)); | ||
226 | break; | ||
227 | case ISCSI_NET_PARAM_IPV6_LINKLOCAL: | ||
228 | if (iface_param->iface_num & 0x1) | ||
229 | break; | ||
230 | memcpy(init_fw_cb->ipv6_if_id, &iface_param->value[8], | ||
231 | sizeof(init_fw_cb->ipv6_if_id)); | ||
232 | break; | ||
233 | case ISCSI_NET_PARAM_IPV6_ROUTER: | ||
234 | if (iface_param->iface_num & 0x1) | ||
235 | break; | ||
236 | memcpy(init_fw_cb->ipv6_dflt_rtr_addr, iface_param->value, | ||
237 | sizeof(init_fw_cb->ipv6_dflt_rtr_addr)); | ||
238 | break; | ||
239 | case ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG: | ||
240 | /* Autocfg applies to even interface */ | ||
241 | if (iface_param->iface_num & 0x1) | ||
242 | break; | ||
243 | |||
244 | if (iface_param->value[0] == ISCSI_IPV6_AUTOCFG_DISABLE) | ||
245 | init_fw_cb->ipv6_addtl_opts &= | ||
246 | cpu_to_le16( | ||
247 | ~IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE); | ||
248 | else if (iface_param->value[0] == ISCSI_IPV6_AUTOCFG_ND_ENABLE) | ||
249 | init_fw_cb->ipv6_addtl_opts |= | ||
250 | cpu_to_le16( | ||
251 | IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE); | ||
252 | else | ||
253 | ql4_printk(KERN_ERR, ha, "Invalid autocfg setting for " | ||
254 | "IPv6 addr\n"); | ||
255 | break; | ||
256 | case ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG: | ||
257 | /* Autocfg applies to even interface */ | ||
258 | if (iface_param->iface_num & 0x1) | ||
259 | break; | ||
260 | |||
261 | if (iface_param->value[0] == | ||
262 | ISCSI_IPV6_LINKLOCAL_AUTOCFG_ENABLE) | ||
263 | init_fw_cb->ipv6_addtl_opts |= cpu_to_le16( | ||
264 | IPV6_ADDOPT_AUTOCONFIG_LINK_LOCAL_ADDR); | ||
265 | else if (iface_param->value[0] == | ||
266 | ISCSI_IPV6_LINKLOCAL_AUTOCFG_DISABLE) | ||
267 | init_fw_cb->ipv6_addtl_opts &= cpu_to_le16( | ||
268 | ~IPV6_ADDOPT_AUTOCONFIG_LINK_LOCAL_ADDR); | ||
269 | else | ||
270 | ql4_printk(KERN_ERR, ha, "Invalid autocfg setting for " | ||
271 | "IPv6 linklocal addr\n"); | ||
272 | break; | ||
273 | case ISCSI_NET_PARAM_IPV6_ROUTER_AUTOCFG: | ||
274 | /* Autocfg applies to even interface */ | ||
275 | if (iface_param->iface_num & 0x1) | ||
276 | break; | ||
277 | |||
278 | if (iface_param->value[0] == ISCSI_IPV6_ROUTER_AUTOCFG_ENABLE) | ||
279 | memset(init_fw_cb->ipv6_dflt_rtr_addr, 0, | ||
280 | sizeof(init_fw_cb->ipv6_dflt_rtr_addr)); | ||
281 | break; | ||
282 | case ISCSI_NET_PARAM_IFACE_ENABLE: | ||
283 | if (iface_param->value[0] == ISCSI_IFACE_ENABLE) | ||
284 | init_fw_cb->ipv6_opts |= | ||
285 | cpu_to_le16(IPV6_OPT_IPV6_PROTOCOL_ENABLE); | ||
286 | else | ||
287 | init_fw_cb->ipv6_opts &= | ||
288 | cpu_to_le16(~IPV6_OPT_IPV6_PROTOCOL_ENABLE & | ||
289 | 0xFFFF); | ||
290 | break; | ||
291 | case ISCSI_NET_PARAM_VLAN_ID: | ||
292 | if (iface_param->len != sizeof(init_fw_cb->ipv6_vlan_tag)) | ||
293 | break; | ||
294 | init_fw_cb->ipv6_vlan_tag = *(uint16_t *)iface_param->value; | ||
295 | break; | ||
296 | default: | ||
297 | ql4_printk(KERN_ERR, ha, "Unknown IPv6 param = %d\n", | ||
298 | iface_param->param); | ||
299 | break; | ||
300 | } | ||
301 | } | ||
302 | |||
303 | static void qla4xxx_set_ipv4(struct scsi_qla_host *ha, | ||
304 | struct iscsi_iface_param_info *iface_param, | ||
305 | struct addr_ctrl_blk *init_fw_cb) | ||
306 | { | ||
307 | switch (iface_param->param) { | ||
308 | case ISCSI_NET_PARAM_IPV4_ADDR: | ||
309 | memcpy(init_fw_cb->ipv4_addr, iface_param->value, | ||
310 | sizeof(init_fw_cb->ipv4_addr)); | ||
311 | break; | ||
312 | case ISCSI_NET_PARAM_IPV4_SUBNET: | ||
313 | memcpy(init_fw_cb->ipv4_subnet, iface_param->value, | ||
314 | sizeof(init_fw_cb->ipv4_subnet)); | ||
315 | break; | ||
316 | case ISCSI_NET_PARAM_IPV4_GW: | ||
317 | memcpy(init_fw_cb->ipv4_gw_addr, iface_param->value, | ||
318 | sizeof(init_fw_cb->ipv4_gw_addr)); | ||
319 | break; | ||
320 | case ISCSI_NET_PARAM_IPV4_BOOTPROTO: | ||
321 | if (iface_param->value[0] == ISCSI_BOOTPROTO_DHCP) | ||
322 | init_fw_cb->ipv4_tcp_opts |= | ||
323 | cpu_to_le16(TCPOPT_DHCP_ENABLE); | ||
324 | else if (iface_param->value[0] == ISCSI_BOOTPROTO_STATIC) | ||
325 | init_fw_cb->ipv4_tcp_opts &= | ||
326 | cpu_to_le16(~TCPOPT_DHCP_ENABLE); | ||
327 | else | ||
328 | ql4_printk(KERN_ERR, ha, "Invalid IPv4 bootproto\n"); | ||
329 | break; | ||
330 | case ISCSI_NET_PARAM_IFACE_ENABLE: | ||
331 | if (iface_param->value[0] == ISCSI_IFACE_ENABLE) | ||
332 | init_fw_cb->ipv4_ip_opts |= | ||
333 | cpu_to_le16(IPOPT_IPv4_PROTOCOL_ENABLE); | ||
334 | else | ||
335 | init_fw_cb->ipv4_ip_opts &= | ||
336 | cpu_to_le16(~IPOPT_IPv4_PROTOCOL_ENABLE & | ||
337 | 0xFFFF); | ||
338 | break; | ||
339 | case ISCSI_NET_PARAM_VLAN_ID: | ||
340 | if (iface_param->len != sizeof(init_fw_cb->ipv4_vlan_tag)) | ||
341 | break; | ||
342 | init_fw_cb->ipv4_vlan_tag = *(uint16_t *)iface_param->value; | ||
343 | break; | ||
344 | default: | ||
345 | ql4_printk(KERN_ERR, ha, "Unknown IPv4 param = %d\n", | ||
346 | iface_param->param); | ||
347 | break; | ||
348 | } | ||
349 | } | ||
350 | |||
351 | static void | ||
352 | qla4xxx_initcb_to_acb(struct addr_ctrl_blk *init_fw_cb) | ||
353 | { | ||
354 | struct addr_ctrl_blk_def *acb; | ||
355 | acb = (struct addr_ctrl_blk_def *)init_fw_cb; | ||
356 | memset(acb->reserved1, 0, sizeof(acb->reserved1)); | ||
357 | memset(acb->reserved2, 0, sizeof(acb->reserved2)); | ||
358 | memset(acb->reserved3, 0, sizeof(acb->reserved3)); | ||
359 | memset(acb->reserved4, 0, sizeof(acb->reserved4)); | ||
360 | memset(acb->reserved5, 0, sizeof(acb->reserved5)); | ||
361 | memset(acb->reserved6, 0, sizeof(acb->reserved6)); | ||
362 | memset(acb->reserved7, 0, sizeof(acb->reserved7)); | ||
363 | memset(acb->reserved8, 0, sizeof(acb->reserved8)); | ||
364 | memset(acb->reserved9, 0, sizeof(acb->reserved9)); | ||
365 | memset(acb->reserved10, 0, sizeof(acb->reserved10)); | ||
366 | memset(acb->reserved11, 0, sizeof(acb->reserved11)); | ||
367 | memset(acb->reserved12, 0, sizeof(acb->reserved12)); | ||
368 | memset(acb->reserved13, 0, sizeof(acb->reserved13)); | ||
369 | memset(acb->reserved14, 0, sizeof(acb->reserved14)); | ||
370 | memset(acb->reserved15, 0, sizeof(acb->reserved15)); | ||
371 | } | ||
372 | |||
373 | static int | ||
374 | qla4xxx_iface_set_param(struct Scsi_Host *shost, char *data, int count) | ||
375 | { | ||
376 | struct scsi_qla_host *ha = to_qla_host(shost); | ||
377 | int rval = 0; | ||
378 | struct iscsi_iface_param_info *iface_param = NULL; | ||
379 | struct addr_ctrl_blk *init_fw_cb = NULL; | ||
380 | dma_addr_t init_fw_cb_dma; | ||
381 | uint32_t mbox_cmd[MBOX_REG_COUNT]; | ||
382 | uint32_t mbox_sts[MBOX_REG_COUNT]; | ||
383 | uint32_t total_param_count; | ||
384 | uint32_t length; | ||
385 | |||
386 | init_fw_cb = dma_alloc_coherent(&ha->pdev->dev, | ||
387 | sizeof(struct addr_ctrl_blk), | ||
388 | &init_fw_cb_dma, GFP_KERNEL); | ||
389 | if (!init_fw_cb) { | ||
390 | ql4_printk(KERN_ERR, ha, "%s: Unable to alloc init_cb\n", | ||
391 | __func__); | ||
392 | return -ENOMEM; | ||
393 | } | ||
394 | |||
395 | memset(init_fw_cb, 0, sizeof(struct addr_ctrl_blk)); | ||
396 | memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | ||
397 | memset(&mbox_sts, 0, sizeof(mbox_sts)); | ||
398 | |||
399 | if (qla4xxx_get_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma)) { | ||
400 | ql4_printk(KERN_ERR, ha, "%s: get ifcb failed\n", __func__); | ||
401 | rval = -EIO; | ||
402 | goto exit_init_fw_cb; | ||
403 | } | ||
404 | |||
405 | total_param_count = count; | ||
406 | iface_param = (struct iscsi_iface_param_info *)data; | ||
407 | |||
408 | for ( ; total_param_count != 0; total_param_count--) { | ||
409 | length = iface_param->len; | ||
410 | |||
411 | if (iface_param->param_type != ISCSI_NET_PARAM) | ||
412 | continue; | ||
413 | |||
414 | switch (iface_param->iface_type) { | ||
415 | case ISCSI_IFACE_TYPE_IPV4: | ||
416 | switch (iface_param->iface_num) { | ||
417 | case 0: | ||
418 | qla4xxx_set_ipv4(ha, iface_param, init_fw_cb); | ||
419 | break; | ||
420 | default: | ||
421 | /* Cannot have more than one IPv4 interface */ | ||
422 | ql4_printk(KERN_ERR, ha, "Invalid IPv4 iface " | ||
423 | "number = %d\n", | ||
424 | iface_param->iface_num); | ||
425 | break; | ||
426 | } | ||
427 | break; | ||
428 | case ISCSI_IFACE_TYPE_IPV6: | ||
429 | switch (iface_param->iface_num) { | ||
430 | case 0: | ||
431 | case 1: | ||
432 | qla4xxx_set_ipv6(ha, iface_param, init_fw_cb); | ||
433 | break; | ||
434 | default: | ||
435 | /* Cannot have more than two IPv6 interface */ | ||
436 | ql4_printk(KERN_ERR, ha, "Invalid IPv6 iface " | ||
437 | "number = %d\n", | ||
438 | iface_param->iface_num); | ||
439 | break; | ||
440 | } | ||
441 | break; | ||
442 | default: | ||
443 | ql4_printk(KERN_ERR, ha, "Invalid iface type\n"); | ||
444 | break; | ||
445 | } | ||
446 | |||
447 | iface_param = (struct iscsi_iface_param_info *) | ||
448 | ((uint8_t *)iface_param + | ||
449 | sizeof(struct iscsi_iface_param_info) + length); | ||
450 | } | ||
451 | |||
452 | init_fw_cb->cookie = cpu_to_le32(0x11BEAD5A); | ||
453 | |||
454 | rval = qla4xxx_set_flash(ha, init_fw_cb_dma, FLASH_SEGMENT_IFCB, | ||
455 | sizeof(struct addr_ctrl_blk), | ||
456 | FLASH_OPT_RMW_COMMIT); | ||
457 | if (rval != QLA_SUCCESS) { | ||
458 | ql4_printk(KERN_ERR, ha, "%s: set flash mbx failed\n", | ||
459 | __func__); | ||
460 | rval = -EIO; | ||
461 | goto exit_init_fw_cb; | ||
462 | } | ||
463 | |||
464 | qla4xxx_disable_acb(ha); | ||
465 | |||
466 | qla4xxx_initcb_to_acb(init_fw_cb); | ||
467 | |||
468 | rval = qla4xxx_set_acb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma); | ||
469 | if (rval != QLA_SUCCESS) { | ||
470 | ql4_printk(KERN_ERR, ha, "%s: set acb mbx failed\n", | ||
471 | __func__); | ||
472 | rval = -EIO; | ||
473 | goto exit_init_fw_cb; | ||
474 | } | ||
475 | |||
476 | memset(init_fw_cb, 0, sizeof(struct addr_ctrl_blk)); | ||
477 | qla4xxx_update_local_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb, | ||
478 | init_fw_cb_dma); | ||
479 | |||
480 | exit_init_fw_cb: | ||
481 | dma_free_coherent(&ha->pdev->dev, sizeof(struct addr_ctrl_blk), | ||
482 | init_fw_cb, init_fw_cb_dma); | ||
483 | |||
484 | return rval; | ||
485 | } | ||
486 | |||
205 | static int qla4xxx_sess_get_param(struct iscsi_cls_session *sess, | 487 | static int qla4xxx_sess_get_param(struct iscsi_cls_session *sess, |
206 | enum iscsi_param param, char *buf) | 488 | enum iscsi_param param, char *buf) |
207 | { | 489 | { |