aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorMike Christie <michaelc@cs.wisc.edu>2011-07-25 14:48:38 -0400
committerJames Bottomley <JBottomley@Parallels.com>2011-08-27 10:35:58 -0400
commitd00efe3fa87fdf1df3635ba57ef3f14d03bc3ac8 (patch)
tree7af8d1d78aafc96a14ef8f6a9c1f477c493c0497 /drivers/scsi
parent56c155b5ca427c9a6312bb0e31865f1c8ab10b2b (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.h77
-rw-r--r--drivers/scsi/qla4xxx/ql4_glbl.h20
-rw-r--r--drivers/scsi/qla4xxx/ql4_mbx.c119
-rw-r--r--drivers/scsi/qla4xxx/ql4_os.c282
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
586struct 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
579struct dev_db_entry { 656struct 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
53int qla4xxx_set_ddb_entry(struct scsi_qla_host * ha, uint16_t fw_ddb_index, 53int 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 55uint8_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);
57int 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);
61int qla4xxx_disable_acb(struct scsi_qla_host *ha);
62int qla4xxx_set_acb(struct scsi_qla_host *ha, uint32_t *mbox_cmd,
63 uint32_t *mbox_sts, dma_addr_t acb_dma);
64int qla4xxx_get_acb(struct scsi_qla_host *ha, uint32_t *mbox_cmd,
65 uint32_t *mbox_sts, dma_addr_t acb_dma);
56void qla4xxx_mark_device_missing(struct scsi_qla_host *ha, 66void qla4xxx_mark_device_missing(struct scsi_qla_host *ha,
57 struct ddb_entry *ddb_entry); 67 struct ddb_entry *ddb_entry);
58u16 rd_nvram_word(struct scsi_qla_host *ha, int offset); 68u16 rd_nvram_word(struct scsi_qla_host *ha, int offset);
@@ -75,7 +85,8 @@ void qla4xxx_dump_buffer(void *b, uint32_t size);
75int qla4xxx_send_marker_iocb(struct scsi_qla_host *ha, 85int 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);
77int qla4_is_relogin_allowed(struct scsi_qla_host *ha, uint32_t conn_err); 87int qla4_is_relogin_allowed(struct scsi_qla_host *ha, uint32_t conn_err);
78 88int qla4xxx_set_flash(struct scsi_qla_host *ha, dma_addr_t dma_addr,
89 uint32_t offset, uint32_t length, uint32_t options);
79int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, 90int 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);
95void qla4xxx_get_conn_event_log(struct scsi_qla_host *ha); 106void qla4xxx_get_conn_event_log(struct scsi_qla_host *ha);
96void qla4xxx_mailbox_premature_completion(struct scsi_qla_host *ha); 107void qla4xxx_mailbox_premature_completion(struct scsi_qla_host *ha);
97void qla4xxx_dump_registers(struct scsi_qla_host *ha); 108void qla4xxx_dump_registers(struct scsi_qla_host *ha);
109uint8_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
99void qla4_8xxx_pci_config(struct scsi_qla_host *); 115void qla4_8xxx_pci_config(struct scsi_qla_host *);
100int qla4_8xxx_iospace_config(struct scsi_qla_host *ha); 116int 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
306static uint8_t 306uint8_t
307qla4xxx_get_ifcb(struct scsi_qla_host *ha, uint32_t *mbox_cmd, 307qla4xxx_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
366static uint8_t 366uint8_t
367qla4xxx_update_local_ifcb(struct scsi_qla_host *ha, 367qla4xxx_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
1210int 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
1236int 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
1262int 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
1282int 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
1304int 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);
81static int qla4xxx_host_get_param(struct Scsi_Host *shost, 81static 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);
83static int qla4xxx_iface_set_param(struct Scsi_Host *shost, char *data,
84 int count);
83static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session); 85static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session);
84static enum blk_eh_timer_return qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc); 86static 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
208static 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
303static 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
351static void
352qla4xxx_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
373static int
374qla4xxx_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
480exit_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
205static int qla4xxx_sess_get_param(struct iscsi_cls_session *sess, 487static 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{