Commit 1dc5ec24 authored by James Smart's avatar James Smart Committed by Martin K. Petersen

scsi: lpfc: add Trunking support

Add trunking support to the driver. Trunking is found on more recent
asics. In general, trunking appears as a single "port" to the driver
and overall behavior doesn't differ. Link speed is reported as an
aggregate value, while link speed control is done on a per-physical
link basis with all links in the trunk symmetrical. Some commands
returning port information are updated to additionally provide
trunking information. And new ACQEs are generated to report physical
link events relative to the trunk.

This patch contains the following modifications:

- Added link speed settings of 128GB and 256GB.

- Added handling of trunk-related ACQEs, mainly logging and trapping
  of physical link statuses.

- Added additional bsg interface to query trunk state by applications.

- Augment link_state sysfs attribtute to display trunk link status
Signed-off-by: default avatarDick Kennedy <dick.kennedy@broadcom.com>
Signed-off-by: default avatarJames Smart <jsmart2021@gmail.com>
Reviewed-by: default avatarHannes Reinecke <hare@suse.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 7ea92eb4
...@@ -335,6 +335,18 @@ enum hba_state { ...@@ -335,6 +335,18 @@ enum hba_state {
LPFC_HBA_ERROR = -1 LPFC_HBA_ERROR = -1
}; };
struct lpfc_trunk_link_state {
enum hba_state state;
uint8_t fault;
};
struct lpfc_trunk_link {
struct lpfc_trunk_link_state link0,
link1,
link2,
link3;
};
struct lpfc_vport { struct lpfc_vport {
struct lpfc_hba *phba; struct lpfc_hba *phba;
struct list_head listentry; struct list_head listentry;
...@@ -684,6 +696,7 @@ struct lpfc_hba { ...@@ -684,6 +696,7 @@ struct lpfc_hba {
uint32_t iocb_cmd_size; uint32_t iocb_cmd_size;
uint32_t iocb_rsp_size; uint32_t iocb_rsp_size;
struct lpfc_trunk_link trunk_link;
enum hba_state link_state; enum hba_state link_state;
uint32_t link_flag; /* link state flags */ uint32_t link_flag; /* link state flags */
#define LS_LOOPBACK_MODE 0x1 /* NPort is in Loopback mode */ #define LS_LOOPBACK_MODE 0x1 /* NPort is in Loopback mode */
......
...@@ -883,6 +883,42 @@ lpfc_link_state_show(struct device *dev, struct device_attribute *attr, ...@@ -883,6 +883,42 @@ lpfc_link_state_show(struct device *dev, struct device_attribute *attr,
} }
} }
if ((phba->sli_rev == LPFC_SLI_REV4) &&
((bf_get(lpfc_sli_intf_if_type,
&phba->sli4_hba.sli_intf) ==
LPFC_SLI_INTF_IF_TYPE_6))) {
struct lpfc_trunk_link link = phba->trunk_link;
if (bf_get(lpfc_conf_trunk_port0, &phba->sli4_hba))
len += snprintf(buf + len, PAGE_SIZE - len,
"Trunk port 0: Link %s %s\n",
(link.link0.state == LPFC_LINK_UP) ?
"Up" : "Down. ",
trunk_errmsg[link.link0.fault]);
if (bf_get(lpfc_conf_trunk_port1, &phba->sli4_hba))
len += snprintf(buf + len, PAGE_SIZE - len,
"Trunk port 1: Link %s %s\n",
(link.link1.state == LPFC_LINK_UP) ?
"Up" : "Down. ",
trunk_errmsg[link.link1.fault]);
if (bf_get(lpfc_conf_trunk_port2, &phba->sli4_hba))
len += snprintf(buf + len, PAGE_SIZE - len,
"Trunk port 2: Link %s %s\n",
(link.link2.state == LPFC_LINK_UP) ?
"Up" : "Down. ",
trunk_errmsg[link.link2.fault]);
if (bf_get(lpfc_conf_trunk_port3, &phba->sli4_hba))
len += snprintf(buf + len, PAGE_SIZE - len,
"Trunk port 3: Link %s %s\n",
(link.link3.state == LPFC_LINK_UP) ?
"Up" : "Down. ",
trunk_errmsg[link.link3.fault]);
}
return len; return len;
} }
...@@ -1430,6 +1466,66 @@ lpfc_nport_evt_cnt_show(struct device *dev, struct device_attribute *attr, ...@@ -1430,6 +1466,66 @@ lpfc_nport_evt_cnt_show(struct device *dev, struct device_attribute *attr,
return snprintf(buf, PAGE_SIZE, "%d\n", phba->nport_event_cnt); return snprintf(buf, PAGE_SIZE, "%d\n", phba->nport_event_cnt);
} }
int
lpfc_set_trunking(struct lpfc_hba *phba, char *buff_out)
{
LPFC_MBOXQ_t *mbox = NULL;
unsigned long val = 0;
char *pval = 0;
int rc = 0;
if (!strncmp("enable", buff_out,
strlen("enable"))) {
pval = buff_out + strlen("enable") + 1;
rc = kstrtoul(pval, 0, &val);
if (rc)
return rc; /* Invalid number */
} else if (!strncmp("disable", buff_out,
strlen("disable"))) {
val = 0;
} else {
return -EINVAL; /* Invalid command */
}
switch (val) {
case 0:
val = 0x0; /* Disable */
break;
case 2:
val = 0x1; /* Enable two port trunk */
break;
case 4:
val = 0x2; /* Enable four port trunk */
break;
default:
return -EINVAL;
}
lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
"0070 Set trunk mode with val %ld ", val);
mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!mbox)
return -ENOMEM;
lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE,
LPFC_MBOX_OPCODE_FCOE_FC_SET_TRUNK_MODE,
12, LPFC_SLI4_MBX_EMBED);
bf_set(lpfc_mbx_set_trunk_mode,
&mbox->u.mqe.un.set_trunk_mode,
val);
rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
if (rc)
lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
"0071 Set trunk mode failed with status: %d",
rc);
if (rc != MBX_TIMEOUT)
mempool_free(mbox, phba->mbox_mem_pool);
return 0;
}
/** /**
* lpfc_board_mode_show - Return the state of the board * lpfc_board_mode_show - Return the state of the board
* @dev: class device that is converted into a Scsi_host. * @dev: class device that is converted into a Scsi_host.
...@@ -1522,6 +1618,8 @@ lpfc_board_mode_store(struct device *dev, struct device_attribute *attr, ...@@ -1522,6 +1618,8 @@ lpfc_board_mode_store(struct device *dev, struct device_attribute *attr,
status = lpfc_sli4_pdev_reg_request(phba, LPFC_FW_RESET); status = lpfc_sli4_pdev_reg_request(phba, LPFC_FW_RESET);
else if (strncmp(buf, "dv_reset", sizeof("dv_reset") - 1) == 0) else if (strncmp(buf, "dv_reset", sizeof("dv_reset") - 1) == 0)
status = lpfc_sli4_pdev_reg_request(phba, LPFC_DV_RESET); status = lpfc_sli4_pdev_reg_request(phba, LPFC_DV_RESET);
else if (strncmp(buf, "trunk", sizeof("trunk") - 1) == 0)
status = lpfc_set_trunking(phba, (char *)buf + sizeof("trunk"));
else else
status = -EINVAL; status = -EINVAL;
...@@ -6019,6 +6117,9 @@ lpfc_get_host_speed(struct Scsi_Host *shost) ...@@ -6019,6 +6117,9 @@ lpfc_get_host_speed(struct Scsi_Host *shost)
case LPFC_LINK_SPEED_64GHZ: case LPFC_LINK_SPEED_64GHZ:
fc_host_speed(shost) = FC_PORTSPEED_64GBIT; fc_host_speed(shost) = FC_PORTSPEED_64GBIT;
break; break;
case LPFC_LINK_SPEED_128GHZ:
fc_host_speed(shost) = FC_PORTSPEED_128GBIT;
break;
default: default:
fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN; fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
break; break;
......
...@@ -5615,6 +5615,77 @@ lpfc_bsg_get_ras_fwlog(struct bsg_job *job) ...@@ -5615,6 +5615,77 @@ lpfc_bsg_get_ras_fwlog(struct bsg_job *job)
return rc; return rc;
} }
static int
lpfc_get_trunk_info(struct bsg_job *job)
{
struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job));
struct lpfc_hba *phba = vport->phba;
struct fc_bsg_reply *bsg_reply = job->reply;
struct lpfc_trunk_info *event_reply;
int rc = 0;
if (job->request_len <
sizeof(struct fc_bsg_request) + sizeof(struct get_trunk_info_req)) {
lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
"2744 Received GET TRUNK _INFO request below "
"minimum size\n");
rc = -EINVAL;
goto job_error;
}
event_reply = (struct lpfc_trunk_info *)
bsg_reply->reply_data.vendor_reply.vendor_rsp;
if (job->reply_len <
sizeof(struct fc_bsg_request) + sizeof(struct lpfc_trunk_info)) {
lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
"2728 Received GET TRUNK _INFO reply below "
"minimum size\n");
rc = -EINVAL;
goto job_error;
}
if (event_reply == NULL) {
rc = -EINVAL;
goto job_error;
}
bsg_bf_set(lpfc_trunk_info_link_status, event_reply,
(phba->link_state >= LPFC_LINK_UP) ? 1 : 0);
bsg_bf_set(lpfc_trunk_info_trunk_active0, event_reply,
(phba->trunk_link.link0.state == LPFC_LINK_UP) ? 1 : 0);
bsg_bf_set(lpfc_trunk_info_trunk_active1, event_reply,
(phba->trunk_link.link1.state == LPFC_LINK_UP) ? 1 : 0);
bsg_bf_set(lpfc_trunk_info_trunk_active2, event_reply,
(phba->trunk_link.link2.state == LPFC_LINK_UP) ? 1 : 0);
bsg_bf_set(lpfc_trunk_info_trunk_active3, event_reply,
(phba->trunk_link.link3.state == LPFC_LINK_UP) ? 1 : 0);
bsg_bf_set(lpfc_trunk_info_trunk_config0, event_reply,
bf_get(lpfc_conf_trunk_port0, &phba->sli4_hba));
bsg_bf_set(lpfc_trunk_info_trunk_config1, event_reply,
bf_get(lpfc_conf_trunk_port1, &phba->sli4_hba));
bsg_bf_set(lpfc_trunk_info_trunk_config2, event_reply,
bf_get(lpfc_conf_trunk_port2, &phba->sli4_hba));
bsg_bf_set(lpfc_trunk_info_trunk_config3, event_reply,
bf_get(lpfc_conf_trunk_port3, &phba->sli4_hba));
event_reply->port_speed = phba->sli4_hba.link_state.speed / 1000;
event_reply->logical_speed =
phba->sli4_hba.link_state.logical_speed / 100;
job_error:
bsg_reply->result = rc;
bsg_job_done(job, bsg_reply->result,
bsg_reply->reply_payload_rcv_len);
return rc;
}
/** /**
* lpfc_bsg_hst_vendor - process a vendor-specific fc_bsg_job * lpfc_bsg_hst_vendor - process a vendor-specific fc_bsg_job
...@@ -5675,6 +5746,9 @@ lpfc_bsg_hst_vendor(struct bsg_job *job) ...@@ -5675,6 +5746,9 @@ lpfc_bsg_hst_vendor(struct bsg_job *job)
case LPFC_BSG_VENDOR_RAS_SET_CONFIG: case LPFC_BSG_VENDOR_RAS_SET_CONFIG:
rc = lpfc_bsg_set_ras_config(job); rc = lpfc_bsg_set_ras_config(job);
break; break;
case LPFC_BSG_VENDOR_GET_TRUNK_INFO:
rc = lpfc_get_trunk_info(job);
break;
default: default:
rc = -EINVAL; rc = -EINVAL;
bsg_reply->reply_payload_rcv_len = 0; bsg_reply->reply_payload_rcv_len = 0;
......
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
#define LPFC_BSG_VENDOR_RAS_GET_FWLOG 17 #define LPFC_BSG_VENDOR_RAS_GET_FWLOG 17
#define LPFC_BSG_VENDOR_RAS_GET_CONFIG 18 #define LPFC_BSG_VENDOR_RAS_GET_CONFIG 18
#define LPFC_BSG_VENDOR_RAS_SET_CONFIG 19 #define LPFC_BSG_VENDOR_RAS_SET_CONFIG 19
#define LPFC_BSG_VENDOR_GET_TRUNK_INFO 20
struct set_ct_event { struct set_ct_event {
uint32_t command; uint32_t command;
...@@ -331,6 +332,43 @@ struct lpfc_bsg_get_ras_config_reply { ...@@ -331,6 +332,43 @@ struct lpfc_bsg_get_ras_config_reply {
uint32_t log_buff_sz; uint32_t log_buff_sz;
}; };
struct lpfc_trunk_info {
uint32_t word0;
#define lpfc_trunk_info_link_status_SHIFT 0
#define lpfc_trunk_info_link_status_MASK 1
#define lpfc_trunk_info_link_status_WORD word0
#define lpfc_trunk_info_trunk_active0_SHIFT 8
#define lpfc_trunk_info_trunk_active0_MASK 1
#define lpfc_trunk_info_trunk_active0_WORD word0
#define lpfc_trunk_info_trunk_active1_SHIFT 9
#define lpfc_trunk_info_trunk_active1_MASK 1
#define lpfc_trunk_info_trunk_active1_WORD word0
#define lpfc_trunk_info_trunk_active2_SHIFT 10
#define lpfc_trunk_info_trunk_active2_MASK 1
#define lpfc_trunk_info_trunk_active2_WORD word0
#define lpfc_trunk_info_trunk_active3_SHIFT 11
#define lpfc_trunk_info_trunk_active3_MASK 1
#define lpfc_trunk_info_trunk_active3_WORD word0
#define lpfc_trunk_info_trunk_config0_SHIFT 12
#define lpfc_trunk_info_trunk_config0_MASK 1
#define lpfc_trunk_info_trunk_config0_WORD word0
#define lpfc_trunk_info_trunk_config1_SHIFT 13
#define lpfc_trunk_info_trunk_config1_MASK 1
#define lpfc_trunk_info_trunk_config1_WORD word0
#define lpfc_trunk_info_trunk_config2_SHIFT 14
#define lpfc_trunk_info_trunk_config2_MASK 1
#define lpfc_trunk_info_trunk_config2_WORD word0
#define lpfc_trunk_info_trunk_config3_SHIFT 15
#define lpfc_trunk_info_trunk_config3_MASK 1
#define lpfc_trunk_info_trunk_config3_WORD word0
uint16_t port_speed;
uint16_t logical_speed;
uint32_t reserved3;
};
struct get_trunk_info_req {
uint32_t command;
};
/* driver only */ /* driver only */
#define SLI_CONFIG_NOT_HANDLED 0 #define SLI_CONFIG_NOT_HANDLED 0
......
...@@ -2340,6 +2340,8 @@ lpfc_fdmi_port_attr_support_speed(struct lpfc_vport *vport, ...@@ -2340,6 +2340,8 @@ lpfc_fdmi_port_attr_support_speed(struct lpfc_vport *vport,
ae->un.AttrInt = 0; ae->un.AttrInt = 0;
if (!(phba->hba_flag & HBA_FCOE_MODE)) { if (!(phba->hba_flag & HBA_FCOE_MODE)) {
if (phba->lmt & LMT_128Gb)
ae->un.AttrInt |= HBA_PORTSPEED_128GFC;
if (phba->lmt & LMT_64Gb) if (phba->lmt & LMT_64Gb)
ae->un.AttrInt |= HBA_PORTSPEED_64GFC; ae->un.AttrInt |= HBA_PORTSPEED_64GFC;
if (phba->lmt & LMT_32Gb) if (phba->lmt & LMT_32Gb)
...@@ -2416,6 +2418,9 @@ lpfc_fdmi_port_attr_speed(struct lpfc_vport *vport, ...@@ -2416,6 +2418,9 @@ lpfc_fdmi_port_attr_speed(struct lpfc_vport *vport,
case LPFC_LINK_SPEED_64GHZ: case LPFC_LINK_SPEED_64GHZ:
ae->un.AttrInt = HBA_PORTSPEED_64GFC; ae->un.AttrInt = HBA_PORTSPEED_64GFC;
break; break;
case LPFC_LINK_SPEED_128GHZ:
ae->un.AttrInt = HBA_PORTSPEED_128GFC;
break;
default: default:
ae->un.AttrInt = HBA_PORTSPEED_UNKNOWN; ae->un.AttrInt = HBA_PORTSPEED_UNKNOWN;
break; break;
......
...@@ -5377,6 +5377,8 @@ lpfc_rdp_res_speed(struct fc_rdp_port_speed_desc *desc, struct lpfc_hba *phba) ...@@ -5377,6 +5377,8 @@ lpfc_rdp_res_speed(struct fc_rdp_port_speed_desc *desc, struct lpfc_hba *phba)
desc->info.port_speed.speed = cpu_to_be16(rdp_speed); desc->info.port_speed.speed = cpu_to_be16(rdp_speed);
if (phba->lmt & LMT_128Gb)
rdp_cap |= RDP_PS_128GB;
if (phba->lmt & LMT_64Gb) if (phba->lmt & LMT_64Gb)
rdp_cap |= RDP_PS_64GB; rdp_cap |= RDP_PS_64GB;
if (phba->lmt & LMT_32Gb) if (phba->lmt & LMT_32Gb)
......
...@@ -3114,6 +3114,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la) ...@@ -3114,6 +3114,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la)
case LPFC_LINK_SPEED_16GHZ: case LPFC_LINK_SPEED_16GHZ:
case LPFC_LINK_SPEED_32GHZ: case LPFC_LINK_SPEED_32GHZ:
case LPFC_LINK_SPEED_64GHZ: case LPFC_LINK_SPEED_64GHZ:
case LPFC_LINK_SPEED_128GHZ:
break; break;
default: default:
phba->fc_linkspeed = LPFC_LINK_SPEED_UNKNOWN; phba->fc_linkspeed = LPFC_LINK_SPEED_UNKNOWN;
......
...@@ -1035,6 +1035,7 @@ struct mbox_header { ...@@ -1035,6 +1035,7 @@ struct mbox_header {
#define LPFC_MBOX_OPCODE_FCOE_SET_FCLINK_SETTINGS 0x21 #define LPFC_MBOX_OPCODE_FCOE_SET_FCLINK_SETTINGS 0x21
#define LPFC_MBOX_OPCODE_FCOE_LINK_DIAG_STATE 0x22 #define LPFC_MBOX_OPCODE_FCOE_LINK_DIAG_STATE 0x22
#define LPFC_MBOX_OPCODE_FCOE_LINK_DIAG_LOOPBACK 0x23 #define LPFC_MBOX_OPCODE_FCOE_LINK_DIAG_LOOPBACK 0x23
#define LPFC_MBOX_OPCODE_FCOE_FC_SET_TRUNK_MODE 0x42
/* Low level Opcodes */ /* Low level Opcodes */
#define LPFC_MBOX_OPCODE_SET_DIAG_LOG_OPTION 0x37 #define LPFC_MBOX_OPCODE_SET_DIAG_LOG_OPTION 0x37
...@@ -2781,6 +2782,9 @@ struct lpfc_mbx_read_config { ...@@ -2781,6 +2782,9 @@ struct lpfc_mbx_read_config {
#define lpfc_mbx_rd_conf_lnk_ldv_SHIFT 8 #define lpfc_mbx_rd_conf_lnk_ldv_SHIFT 8
#define lpfc_mbx_rd_conf_lnk_ldv_MASK 0x00000001 #define lpfc_mbx_rd_conf_lnk_ldv_MASK 0x00000001
#define lpfc_mbx_rd_conf_lnk_ldv_WORD word2 #define lpfc_mbx_rd_conf_lnk_ldv_WORD word2
#define lpfc_mbx_rd_conf_trunk_SHIFT 12
#define lpfc_mbx_rd_conf_trunk_MASK 0x0000000F
#define lpfc_mbx_rd_conf_trunk_WORD word2
#define lpfc_mbx_rd_conf_topology_SHIFT 24 #define lpfc_mbx_rd_conf_topology_SHIFT 24
#define lpfc_mbx_rd_conf_topology_MASK 0x000000FF #define lpfc_mbx_rd_conf_topology_MASK 0x000000FF
#define lpfc_mbx_rd_conf_topology_WORD word2 #define lpfc_mbx_rd_conf_topology_WORD word2
...@@ -3516,6 +3520,15 @@ struct lpfc_mbx_set_host_data { ...@@ -3516,6 +3520,15 @@ struct lpfc_mbx_set_host_data {
uint8_t data[LPFC_HOST_OS_DRIVER_VERSION_SIZE]; uint8_t data[LPFC_HOST_OS_DRIVER_VERSION_SIZE];
}; };
struct lpfc_mbx_set_trunk_mode {
struct mbox_header header;
uint32_t word0;
#define lpfc_mbx_set_trunk_mode_WORD word0
#define lpfc_mbx_set_trunk_mode_SHIFT 0
#define lpfc_mbx_set_trunk_mode_MASK 0xFF
uint32_t word1;
uint32_t word2;
};
struct lpfc_mbx_get_sli4_parameters { struct lpfc_mbx_get_sli4_parameters {
struct mbox_header header; struct mbox_header header;
...@@ -3915,6 +3928,7 @@ struct lpfc_mqe { ...@@ -3915,6 +3928,7 @@ struct lpfc_mqe {
struct lpfc_mbx_set_feature set_feature; struct lpfc_mbx_set_feature set_feature;
struct lpfc_mbx_memory_dump_type3 mem_dump_type3; struct lpfc_mbx_memory_dump_type3 mem_dump_type3;
struct lpfc_mbx_set_host_data set_host_data; struct lpfc_mbx_set_host_data set_host_data;
struct lpfc_mbx_set_trunk_mode set_trunk_mode;
struct lpfc_mbx_nop nop; struct lpfc_mbx_nop nop;
struct lpfc_mbx_set_ras_fwlog ras_fwlog; struct lpfc_mbx_set_ras_fwlog ras_fwlog;
} un; } un;
...@@ -4051,6 +4065,23 @@ struct lpfc_acqe_grp5 { ...@@ -4051,6 +4065,23 @@ struct lpfc_acqe_grp5 {
uint32_t trailer; uint32_t trailer;
}; };
static char *const trunk_errmsg[] = { /* map errcode */
"", /* There is no such error code at index 0*/
"link negotiated speed does not match existing"
" trunk - link was \"low\" speed",
"link negotiated speed does not match"
" existing trunk - link was \"middle\" speed",
"link negotiated speed does not match existing"
" trunk - link was \"high\" speed",
"Attached to non-trunking port - F_Port",
"Attached to non-trunking port - N_Port",
"FLOGI response timeout",
"non-FLOGI frame received",
"Invalid FLOGI response",
"Trunking initialization protocol",
"Trunk peer device mismatch",
};
struct lpfc_acqe_fc_la { struct lpfc_acqe_fc_la {
uint32_t word0; uint32_t word0;
#define lpfc_acqe_fc_la_speed_SHIFT 24 #define lpfc_acqe_fc_la_speed_SHIFT 24
...@@ -4084,6 +4115,7 @@ struct lpfc_acqe_fc_la { ...@@ -4084,6 +4115,7 @@ struct lpfc_acqe_fc_la {
#define LPFC_FC_LA_TYPE_MDS_LINK_DOWN 0x4 #define LPFC_FC_LA_TYPE_MDS_LINK_DOWN 0x4
#define LPFC_FC_LA_TYPE_MDS_LOOPBACK 0x5 #define LPFC_FC_LA_TYPE_MDS_LOOPBACK 0x5
#define LPFC_FC_LA_TYPE_UNEXP_WWPN 0x6 #define LPFC_FC_LA_TYPE_UNEXP_WWPN 0x6
#define LPFC_FC_LA_TYPE_TRUNKING_EVENT 0x7
#define lpfc_acqe_fc_la_port_type_SHIFT 6 #define lpfc_acqe_fc_la_port_type_SHIFT 6
#define lpfc_acqe_fc_la_port_type_MASK 0x00000003 #define lpfc_acqe_fc_la_port_type_MASK 0x00000003
#define lpfc_acqe_fc_la_port_type_WORD word0 #define lpfc_acqe_fc_la_port_type_WORD word0
...@@ -4092,6 +4124,32 @@ struct lpfc_acqe_fc_la { ...@@ -4092,6 +4124,32 @@ struct lpfc_acqe_fc_la {
#define lpfc_acqe_fc_la_port_number_SHIFT 0 #define lpfc_acqe_fc_la_port_number_SHIFT 0
#define lpfc_acqe_fc_la_port_number_MASK 0x0000003F #define lpfc_acqe_fc_la_port_number_MASK 0x0000003F
#define lpfc_acqe_fc_la_port_number_WORD word0 #define lpfc_acqe_fc_la_port_number_WORD word0
/* Attention Type is 0x07 (Trunking Event) word0 */
#define lpfc_acqe_fc_la_trunk_link_status_port0_SHIFT 16
#define lpfc_acqe_fc_la_trunk_link_status_port0_MASK 0x0000001
#define lpfc_acqe_fc_la_trunk_link_status_port0_WORD word0
#define lpfc_acqe_fc_la_trunk_link_status_port1_SHIFT 17
#define lpfc_acqe_fc_la_trunk_link_status_port1_MASK 0x0000001
#define lpfc_acqe_fc_la_trunk_link_status_port1_WORD word0
#define lpfc_acqe_fc_la_trunk_link_status_port2_SHIFT 18
#define lpfc_acqe_fc_la_trunk_link_status_port2_MASK 0x0000001
#define lpfc_acqe_fc_la_trunk_link_status_port2_WORD word0
#define lpfc_acqe_fc_la_trunk_link_status_port3_SHIFT 19
#define lpfc_acqe_fc_la_trunk_link_status_port3_MASK 0x0000001
#define lpfc_acqe_fc_la_trunk_link_status_port3_WORD word0
#define lpfc_acqe_fc_la_trunk_config_port0_SHIFT 20
#define lpfc_acqe_fc_la_trunk_config_port0_MASK 0x0000001
#define lpfc_acqe_fc_la_trunk_config_port0_WORD word0
#define lpfc_acqe_fc_la_trunk_config_port1_SHIFT 21
#define lpfc_acqe_fc_la_trunk_config_port1_MASK 0x0000001
#define lpfc_acqe_fc_la_trunk_config_port1_WORD word0
#define lpfc_acqe_fc_la_trunk_config_port2_SHIFT 22
#define lpfc_acqe_fc_la_trunk_config_port2_MASK 0x0000001
#define lpfc_acqe_fc_la_trunk_config_port2_WORD word0
#define lpfc_acqe_fc_la_trunk_config_port3_SHIFT 23
#define lpfc_acqe_fc_la_trunk_config_port3_MASK 0x0000001
#define lpfc_acqe_fc_la_trunk_config_port3_WORD word0
uint32_t word1; uint32_t word1;
#define lpfc_acqe_fc_la_llink_spd_SHIFT 16 #define lpfc_acqe_fc_la_llink_spd_SHIFT 16
#define lpfc_acqe_fc_la_llink_spd_MASK 0x0000FFFF #define lpfc_acqe_fc_la_llink_spd_MASK 0x0000FFFF
...@@ -4099,6 +4157,12 @@ struct lpfc_acqe_fc_la { ...@@ -4099,6 +4157,12 @@ struct lpfc_acqe_fc_la {
#define lpfc_acqe_fc_la_fault_SHIFT 0 #define lpfc_acqe_fc_la_fault_SHIFT 0
#define lpfc_acqe_fc_la_fault_MASK 0x000000FF #define lpfc_acqe_fc_la_fault_MASK 0x000000FF
#define lpfc_acqe_fc_la_fault_WORD word1 #define lpfc_acqe_fc_la_fault_WORD word1
#define lpfc_acqe_fc_la_trunk_fault_SHIFT 0
#define lpfc_acqe_fc_la_trunk_fault_MASK 0x0000000F
#define lpfc_acqe_fc_la_trunk_fault_WORD word1
#define lpfc_acqe_fc_la_trunk_linkmask_SHIFT 4
#define lpfc_acqe_fc_la_trunk_linkmask_MASK 0x000000F
#define lpfc_acqe_fc_la_trunk_linkmask_WORD word1
#define LPFC_FC_LA_FAULT_NONE 0x0 #define LPFC_FC_LA_FAULT_NONE 0x0
#define LPFC_FC_LA_FAULT_LOCAL 0x1 #define LPFC_FC_LA_FAULT_LOCAL 0x1
#define LPFC_FC_LA_FAULT_REMOTE 0x2 #define LPFC_FC_LA_FAULT_REMOTE 0x2
......
...@@ -4108,6 +4108,8 @@ void lpfc_host_supported_speeds_set(struct Scsi_Host *shost) ...@@ -4108,6 +4108,8 @@ void lpfc_host_supported_speeds_set(struct Scsi_Host *shost)
struct lpfc_hba *phba = vport->phba; struct lpfc_hba *phba = vport->phba;
fc_host_supported_speeds(shost) = 0; fc_host_supported_speeds(shost) = 0;
if (phba->lmt & LMT_128Gb)
fc_host_supported_speeds(shost) |= FC_PORTSPEED_128GBIT;
if (phba->lmt & LMT_64Gb) if (phba->lmt & LMT_64Gb)
fc_host_supported_speeds(shost) |= FC_PORTSPEED_64GBIT; fc_host_supported_speeds(shost) |= FC_PORTSPEED_64GBIT;
if (phba->lmt & LMT_32Gb) if (phba->lmt & LMT_32Gb)
...@@ -4471,6 +4473,9 @@ lpfc_sli4_port_speed_parse(struct lpfc_hba *phba, uint32_t evt_code, ...@@ -4471,6 +4473,9 @@ lpfc_sli4_port_speed_parse(struct lpfc_hba *phba, uint32_t evt_code,
case LPFC_FC_LA_SPEED_64G: case LPFC_FC_LA_SPEED_64G:
port_speed = 64000; port_speed = 64000;
break; break;
case LPFC_FC_LA_SPEED_128G:
port_speed = 128000;
break;
default: default:
port_speed = 0; port_speed = 0;
} }
...@@ -4612,6 +4617,140 @@ lpfc_sli4_async_link_evt(struct lpfc_hba *phba, ...@@ -4612,6 +4617,140 @@ lpfc_sli4_async_link_evt(struct lpfc_hba *phba,
mempool_free(pmb, phba->mbox_mem_pool); mempool_free(pmb, phba->mbox_mem_pool);
} }
/**
* lpfc_async_link_speed_to_read_top - Parse async evt link speed code to read
* topology.
* @phba: pointer to lpfc hba data structure.
* @evt_code: asynchronous event code.
* @speed_code: asynchronous event link speed code.
*
* This routine is to parse the giving SLI4 async event link speed code into
* value of Read topology link speed.
*
* Return: link speed in terms of Read topology.
**/
static uint8_t
lpfc_async_link_speed_to_read_top(struct lpfc_hba *phba, uint8_t speed_code)
{
uint8_t port_speed;
switch (speed_code) {
case LPFC_FC_LA_SPEED_1G:
port_speed = LPFC_LINK_SPEED_1GHZ;
break;
case LPFC_FC_LA_SPEED_2G:
port_speed = LPFC_LINK_SPEED_2GHZ;
break;
case LPFC_FC_LA_SPEED_4G:
port_speed = LPFC_LINK_SPEED_4GHZ;
break;
case LPFC_FC_LA_SPEED_8G:
port_speed = LPFC_LINK_SPEED_8GHZ;
break;
case LPFC_FC_LA_SPEED_16G:
port_speed = LPFC_LINK_SPEED_16GHZ;
break;
case LPFC_FC_LA_SPEED_32G:
port_speed = LPFC_LINK_SPEED_32GHZ;
break;
case LPFC_FC_LA_SPEED_64G:
port_speed = LPFC_LINK_SPEED_64GHZ;
break;
case LPFC_FC_LA_SPEED_128G:
port_speed = LPFC_LINK_SPEED_128GHZ;
break;
case LPFC_FC_LA_SPEED_256G:
port_speed = LPFC_LINK_SPEED_256GHZ;
break;
default:
port_speed = 0;
break;
}
return port_speed;
}
#define trunk_link_status(__idx)\
bf_get(lpfc_acqe_fc_la_trunk_config_port##__idx, acqe_fc) ?\
((phba->trunk_link.link##__idx.state == LPFC_LINK_UP) ?\
"Link up" : "Link down") : "NA"
/* Did port __idx reported an error */
#define trunk_port_fault(__idx)\
bf_get(lpfc_acqe_fc_la_trunk_config_port##__idx, acqe_fc) ?\
(port_fault & (1 << __idx) ? "YES" : "NO") : "NA"
static void
lpfc_update_trunk_link_status(struct lpfc_hba *phba,
struct lpfc_acqe_fc_la *acqe_fc)
{
uint8_t port_fault = bf_get(lpfc_acqe_fc_la_trunk_linkmask, acqe_fc);
uint8_t err = bf_get(lpfc_acqe_fc_la_trunk_fault, acqe_fc);
phba->sli4_hba.link_state.speed =
lpfc_sli4_port_speed_parse(phba, LPFC_TRAILER_CODE_FC,
bf_get(lpfc_acqe_fc_la_speed, acqe_fc));
phba->sli4_hba.link_state.logical_speed =
bf_get(lpfc_acqe_fc_la_llink_spd, acqe_fc);
/* We got FC link speed, convert to fc_linkspeed (READ_TOPOLOGY) */
phba->fc_linkspeed =
lpfc_async_link_speed_to_read_top(
phba,
bf_get(lpfc_acqe_fc_la_speed, acqe_fc));
if (bf_get(lpfc_acqe_fc_la_trunk_config_port0, acqe_fc)) {
phba->trunk_link.link0.state =
bf_get(lpfc_acqe_fc_la_trunk_link_status_port0, acqe_fc)
? LPFC_LINK_UP : LPFC_LINK_DOWN;
if (port_fault & 0x1)
phba->trunk_link.link0.fault = err;
}
if (bf_get(lpfc_acqe_fc_la_trunk_config_port1, acqe_fc)) {
phba->trunk_link.link1.state =
bf_get(lpfc_acqe_fc_la_trunk_link_status_port1, acqe_fc)
? LPFC_LINK_UP : LPFC_LINK_DOWN;
if (port_fault & 0x2)
phba->trunk_link.link1.fault = err;
}
if (bf_get(lpfc_acqe_fc_la_trunk_config_port2, acqe_fc)) {
phba->trunk_link.link2.state =
bf_get(lpfc_acqe_fc_la_trunk_link_status_port2, acqe_fc)
? LPFC_LINK_UP : LPFC_LINK_DOWN;
if (port_fault & 0x4)
phba->trunk_link.link2.fault = err;
}
if (bf_get(lpfc_acqe_fc_la_trunk_config_port3, acqe_fc)) {
phba->trunk_link.link3.state =
bf_get(lpfc_acqe_fc_la_trunk_link_status_port3, acqe_fc)
? LPFC_LINK_UP : LPFC_LINK_DOWN;
if (port_fault & 0x8)
phba->trunk_link.link3.fault = err;
}
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"2910 Async FC Trunking Event - Speed:%d\n"
"\tLogical speed:%d "
"port0: %s port1: %s port2: %s port3: %s\n",
phba->sli4_hba.link_state.speed,
phba->sli4_hba.link_state.logical_speed,
trunk_link_status(0), trunk_link_status(1),
trunk_link_status(2), trunk_link_status(3));
if (port_fault)
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"3202 trunk error:0x%x (%s) seen on port0:%s "
/*
* SLI-4: We have only 0xA error codes
* defined as of now. print an appropriate
* message in case driver needs to be updated.
*/
"port1:%s port2:%s port3:%s\n", err, err > 0xA ?
"UNDEFINED. update driver." : trunk_errmsg[err],
trunk_port_fault(0), trunk_port_fault(1),
trunk_port_fault(2), trunk_port_fault(3));
}
/** /**
* lpfc_sli4_async_fc_evt - Process the asynchronous FC link event * lpfc_sli4_async_fc_evt - Process the asynchronous FC link event
* @phba: pointer to lpfc hba data structure. * @phba: pointer to lpfc hba data structure.
...@@ -4637,6 +4776,13 @@ lpfc_sli4_async_fc_evt(struct lpfc_hba *phba, struct lpfc_acqe_fc_la *acqe_fc) ...@@ -4637,6 +4776,13 @@ lpfc_sli4_async_fc_evt(struct lpfc_hba *phba, struct lpfc_acqe_fc_la *acqe_fc)
bf_get(lpfc_trailer_type, acqe_fc)); bf_get(lpfc_trailer_type, acqe_fc));
return; return;
} }
if (bf_get(lpfc_acqe_fc_la_att_type, acqe_fc) ==
LPFC_FC_LA_TYPE_TRUNKING_EVENT) {
lpfc_update_trunk_link_status(phba, acqe_fc);
return;
}
/* Keep the link status for extra SLI4 state machine reference */ /* Keep the link status for extra SLI4 state machine reference */
phba->sli4_hba.link_state.speed = phba->sli4_hba.link_state.speed =
lpfc_sli4_port_speed_parse(phba, LPFC_TRAILER_CODE_FC, lpfc_sli4_port_speed_parse(phba, LPFC_TRAILER_CODE_FC,
...@@ -7804,6 +7950,8 @@ lpfc_sli4_read_config(struct lpfc_hba *phba) ...@@ -7804,6 +7950,8 @@ lpfc_sli4_read_config(struct lpfc_hba *phba)
phba->sli4_hba.bbscn_params.word0 = rd_config->word8; phba->sli4_hba.bbscn_params.word0 = rd_config->word8;
} }
phba->sli4_hba.conf_trunk =
bf_get(lpfc_mbx_rd_conf_trunk, rd_config);
phba->sli4_hba.extents_in_use = phba->sli4_hba.extents_in_use =
bf_get(lpfc_mbx_rd_conf_extnts_inuse, rd_config); bf_get(lpfc_mbx_rd_conf_extnts_inuse, rd_config);
phba->sli4_hba.max_cfg_param.max_xri = phba->sli4_hba.max_cfg_param.max_xri =
......
...@@ -194,6 +194,10 @@ struct lpfc_scsi_buf { ...@@ -194,6 +194,10 @@ struct lpfc_scsi_buf {
#define NO_MORE_OAS_LUN -1 #define NO_MORE_OAS_LUN -1
#define NOT_OAS_ENABLED_LUN NO_MORE_OAS_LUN #define NOT_OAS_ENABLED_LUN NO_MORE_OAS_LUN
#ifndef FC_PORTSPEED_128GBIT
#define FC_PORTSPEED_128GBIT 0x2000
#endif
#define TXRDY_PAYLOAD_LEN 12 #define TXRDY_PAYLOAD_LEN 12
int lpfc_sli4_scmd_to_wqidx_distr(struct lpfc_hba *phba, int lpfc_sli4_scmd_to_wqidx_distr(struct lpfc_hba *phba,
......
...@@ -7636,7 +7636,18 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) ...@@ -7636,7 +7636,18 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
*/ */
spin_lock_irq(&phba->hbalock); spin_lock_irq(&phba->hbalock);
phba->link_state = LPFC_LINK_DOWN; phba->link_state = LPFC_LINK_DOWN;
/* Check if physical ports are trunked */
if (bf_get(lpfc_conf_trunk_port0, &phba->sli4_hba))
phba->trunk_link.link0.state = LPFC_LINK_DOWN;
if (bf_get(lpfc_conf_trunk_port1, &phba->sli4_hba))
phba->trunk_link.link1.state = LPFC_LINK_DOWN;
if (bf_get(lpfc_conf_trunk_port2, &phba->sli4_hba))
phba->trunk_link.link2.state = LPFC_LINK_DOWN;
if (bf_get(lpfc_conf_trunk_port3, &phba->sli4_hba))
phba->trunk_link.link3.state = LPFC_LINK_DOWN;
spin_unlock_irq(&phba->hbalock); spin_unlock_irq(&phba->hbalock);
if (!(phba->hba_flag & HBA_FCOE_MODE) && if (!(phba->hba_flag & HBA_FCOE_MODE) &&
(phba->hba_flag & LINK_DISABLED)) { (phba->hba_flag & LINK_DISABLED)) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_SLI, lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_SLI,
......
...@@ -718,6 +718,19 @@ struct lpfc_sli4_hba { ...@@ -718,6 +718,19 @@ struct lpfc_sli4_hba {
uint16_t num_online_cpu; uint16_t num_online_cpu;
uint16_t num_present_cpu; uint16_t num_present_cpu;
uint16_t curr_disp_cpu; uint16_t curr_disp_cpu;
uint32_t conf_trunk;
#define lpfc_conf_trunk_port0_WORD conf_trunk
#define lpfc_conf_trunk_port0_SHIFT 0
#define lpfc_conf_trunk_port0_MASK 0x1
#define lpfc_conf_trunk_port1_WORD conf_trunk
#define lpfc_conf_trunk_port1_SHIFT 1
#define lpfc_conf_trunk_port1_MASK 0x1
#define lpfc_conf_trunk_port2_WORD conf_trunk
#define lpfc_conf_trunk_port2_SHIFT 2
#define lpfc_conf_trunk_port2_MASK 0x1
#define lpfc_conf_trunk_port3_WORD conf_trunk
#define lpfc_conf_trunk_port3_SHIFT 3
#define lpfc_conf_trunk_port3_MASK 0x1
}; };
enum lpfc_sge_type { enum lpfc_sge_type {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment