Message ID | 20241018161409.4442-7-kartilak@cisco.com (mailing list archive) |
---|---|
State | Changes Requested |
Headers | show |
Series | Introduce support for Fabric Discovery and... | expand |
On 10/18/24 18:14, Karan Tilak Kumar wrote: > Add support for Fabric-Device Management Interface > (FDMI) by introducing PCI device IDs for Cisco > Hardware. > Introduce a module parameter to enable/disable > FDMI support. > Integrate support for FDMI. > > Reported-by: kernel test robot <lkp@intel.com> > Closes: > https://lore.kernel.org/oe-kbuild-all/202406110734.p2v8dq9v-lkp > @intel.com/ > > Reviewed-by: Sesidhar Baddela <sebaddel@cisco.com> > Co-developed-by: Gian Carlo Boffa <gcboffa@cisco.com> > Signed-off-by: Gian Carlo Boffa <gcboffa@cisco.com> > Co-developed-by: Arulprabhu Ponnusamy <arulponn@cisco.com> > Signed-off-by: Arulprabhu Ponnusamy <arulponn@cisco.com> > Co-developed-by: Arun Easi <aeasi@cisco.com> > Signed-off-by: Arun Easi <aeasi@cisco.com> > Co-developed-by: Karan Tilak Kumar <kartilak@cisco.com> > Signed-off-by: Karan Tilak Kumar <kartilak@cisco.com> > --- > Changes between v4 and v5: > Incorporate review comments from Martin: > Modify attribution appropriately. > Remove spurious newline at the end of fdls_disc.c. > Remove spurious newline at the end of fnic_main.c. > > Changes between v2 and v3: > Incorporate review comments from Hannes: > Replace redundant definitions with standard definitions. > > Changes between v1 and v2: > Incorporate review comments from Hannes from other patches: > Replace pr_info with dev_info. > Replace htonll() with get_unaligned_be64(). > Replace definitions with standard definitions from fc_els.h. > Use standard definitions from scsi_transport_fc.h for > port speeds. > Refactor definitions in struct fnic to avoid cache holes. > Replace memcmp with not equal to operator. > Fix warning from kernel test robot: > Remove version.h > --- > drivers/scsi/fnic/Makefile | 3 +- > drivers/scsi/fnic/fdls_disc.c | 468 ++++++++++++++++++++++ > drivers/scsi/fnic/fnic.h | 72 ++++ > drivers/scsi/fnic/fnic_main.c | 25 ++ > drivers/scsi/fnic/fnic_pci_subsys_devid.c | 131 ++++++ > 5 files changed, 698 insertions(+), 1 deletion(-) > create mode 100644 drivers/scsi/fnic/fnic_pci_subsys_devid.c > > diff --git a/drivers/scsi/fnic/Makefile b/drivers/scsi/fnic/Makefile > index 3bd6b1c8b643..af156c69da0c 100644 > --- a/drivers/scsi/fnic/Makefile > +++ b/drivers/scsi/fnic/Makefile > @@ -16,4 +16,5 @@ fnic-y := \ > vnic_intr.o \ > vnic_rq.o \ > vnic_wq_copy.o \ > - vnic_wq.o > + vnic_wq.o \ > + fnic_pci_subsys_devid.o > diff --git a/drivers/scsi/fnic/fdls_disc.c b/drivers/scsi/fnic/fdls_disc.c > index a9a98ddc3a84..0b1d69ff19df 100644 > --- a/drivers/scsi/fnic/fdls_disc.c > +++ b/drivers/scsi/fnic/fdls_disc.c > @@ -9,11 +9,23 @@ > #include "fdls_fc.h" > #include "fnic_fdls.h" > #include <scsi/fc/fc_fcp.h> > +#include <scsi/scsi_transport_fc.h> > #include <linux/utsname.h> > > #define FC_FC4_TYPE_SCSI 0x08 > +#define PORT_SPEED_BIT_8 8 > +#define PORT_SPEED_BIT_9 9 > +#define PORT_SPEED_BIT_14 14 > +#define PORT_SPEED_BIT_15 15 > > static void fdls_send_rpn_id(struct fnic_iport_s *iport); > +static void fdls_fdmi_register_hba(struct fnic_iport_s *iport); > +static void fdls_fdmi_register_pa(struct fnic_iport_s *iport); > +#define FDLS_FDMI_PLOGI_PENDING 0x1 > +#define FDLS_FDMI_REG_HBA_PENDING 0x2 > +#define FDLS_FDMI_RPA_PENDING 0x4 > +#define FDLS_FDMI_ABORT_PENDING 0x8 > +#define FDLS_FDMI_MAX_RETRY 3 > > /* Frame initialization */ > /* > @@ -84,6 +96,70 @@ struct fc_std_els_prli fnic_std_prli_req = { > .spp_params = cpu_to_be32(0xA2)} > }; > > +/* > + * Variables: > + * sid, port_id, port_name > + */ > +struct fc_std_fdmi_rhba fnic_std_fdmi_rhba = { > + .fchdr = {.fh_r_ctl = FC_RCTL_DD_UNSOL_CTL, > + .fh_d_id = {0xFF, 0XFF, 0XFA}, > + .fh_type = FC_TYPE_CT, .fh_f_ctl = {FNIC_ELS_REQ_FCTL, 0, 0}, > + .fh_rx_id = 0xFFFF}, > + .fc_std_ct_hdr = {.ct_rev = FC_CT_REV, .ct_fs_type = FC_FST_MGMT, > + .ct_fs_subtype = FC_FDMI_SUBTYPE, > + .ct_cmd = cpu_to_be16(FC_FDMI_RHBA)}, > + .num_ports = FNIC_FDMI_NUM_PORTS, > + .num_hba_attributes = FNIC_FDMI_NUM_HBA_ATTRS, > + .type_nn = FNIC_FDMI_TYPE_NODE_NAME, > + .length_nn = FNIC_FDMI_NN_LEN, > + .type_manu = FNIC_FDMI_TYPE_MANUFACTURER, > + .length_manu = FNIC_FDMI_MANU_LEN, > + .manufacturer = FNIC_FDMI_MANUFACTURER, > + .type_serial = FNIC_FDMI_TYPE_SERIAL_NUMBER, > + .length_serial = FNIC_FDMI_SERIAL_LEN, > + .type_model = FNIC_FDMI_TYPE_MODEL, > + .length_model = FNIC_FDMI_MODEL_LEN, > + .type_model_des = FNIC_FDMI_TYPE_MODEL_DES, > + .length_model_des = FNIC_FDMI_MODEL_DES_LEN, > + .model_description = FNIC_FDMI_MODEL_DESCRIPTION, > + .type_hw_ver = FNIC_FDMI_TYPE_HARDWARE_VERSION, > + .length_hw_ver = FNIC_FDMI_HW_VER_LEN, > + .type_dr_ver = FNIC_FDMI_TYPE_DRIVER_VERSION, > + .length_dr_ver = FNIC_FDMI_DR_VER_LEN, > + .type_rom_ver = FNIC_FDMI_TYPE_ROM_VERSION, > + .length_rom_ver = FNIC_FDMI_ROM_VER_LEN, > + .type_fw_ver = FNIC_FDMI_TYPE_FIRMWARE_VERSION, > + .length_fw_ver = FNIC_FDMI_FW_VER_LEN, > +}; > + > +/* > + * Variables > + *sid, port_id, port_name > + */ > +struct fc_std_fdmi_rpa fnic_std_fdmi_rpa = { > + .fchdr = {.fh_r_ctl = FC_RCTL_DD_UNSOL_CTL, > + .fh_d_id = {0xFF, 0xFF, 0xFA}, > + .fh_type = FC_TYPE_CT, .fh_f_ctl = {FNIC_ELS_REQ_FCTL, 0, 0}, > + .fh_rx_id = 0xFFFF}, > + .fc_std_ct_hdr = {.ct_rev = FC_CT_REV, .ct_fs_type = FC_FST_MGMT, > + .ct_fs_subtype = FC_FDMI_SUBTYPE, > + .ct_cmd = cpu_to_be16(FC_FDMI_RPA)}, > + .num_port_attributes = FNIC_FDMI_NUM_PORT_ATTRS, > + .type_fc4 = FNIC_FDMI_TYPE_FC4_TYPES, > + .length_fc4 = FNIC_FDMI_FC4_LEN, > + .type_supp_speed = FNIC_FDMI_TYPE_SUPPORTED_SPEEDS, > + .length_supp_speed = FNIC_FDMI_SUPP_SPEED_LEN, > + .type_cur_speed = FNIC_FDMI_TYPE_CURRENT_SPEED, > + .length_cur_speed = FNIC_FDMI_CUR_SPEED_LEN, > + .type_max_frame_size = FNIC_FDMI_TYPE_MAX_FRAME_SIZE, > + .length_max_frame_size = FNIC_FDMI_MFS_LEN, > + .max_frame_size = FNIC_FDMI_MFS, > + .type_os_name = FNIC_FDMI_TYPE_OS_NAME, > + .length_os_name = FNIC_FDMI_OS_NAME_LEN, > + .type_host_name = FNIC_FDMI_TYPE_HOST_NAME, > + .length_host_name = FNIC_FDMI_HN_LEN, > +}; > + > /* > * Variables: > * fh_s_id, port_id, port_name > @@ -224,6 +300,7 @@ static void fdls_target_restart_nexus(struct fnic_tport_s *tport); > static void fdls_start_tport_timer(struct fnic_iport_s *iport, > struct fnic_tport_s *tport, int timeout); > static void fdls_tport_timer_callback(struct timer_list *t); > +static void fdls_send_fdmi_plogi(struct fnic_iport_s *iport); > static void fdls_start_fabric_timer(struct fnic_iport_s *iport, > int timeout); > static void > @@ -337,6 +414,15 @@ uint16_t fdls_alloc_fabric_oxid(struct fnic_iport_s *iport, > * separately. > */ > switch (exp_rsp_type) { > + case FNIC_FDMI_PLOGI_RSP: > + oxid_pool->active_oxid_fdmi_plogi = oxid; > + break; > + case FNIC_FDMI_REG_HBA_RSP: > + oxid_pool->active_oxid_fdmi_rhba = oxid; > + break; > + case FNIC_FDMI_RPA_RSP: > + oxid_pool->active_oxid_fdmi_rpa = oxid; > + break; > default: > oxid_pool->active_oxid_fabric_req = oxid; > break; > @@ -372,6 +458,21 @@ static inline void fdls_schedule_fabric_oxid_free(struct fnic_iport_s > iport->fabric_oxid_pool.active_oxid_fabric_req); > } > > +static inline void fdls_schedule_fdmi_oxid_free(struct fnic_iport_s *iport) > +{ > + if (iport->fabric.fdmi_pending & FDLS_FDMI_PLOGI_PENDING) > + fdls_schedule_oxid_free(&iport->fdmi_oxid_pool.meta, > + iport->fdmi_oxid_pool.active_oxid_fdmi_plogi); > + > + if (iport->fabric.fdmi_pending & FDLS_FDMI_REG_HBA_PENDING) > + fdls_schedule_oxid_free(&iport->fdmi_oxid_pool.meta, > + iport->fdmi_oxid_pool.active_oxid_fdmi_rhba); > + > + if (iport->fabric.fdmi_pending & FDLS_FDMI_RPA_PENDING) > + fdls_schedule_oxid_free(&iport->fdmi_oxid_pool.meta, > + iport->fdmi_oxid_pool.active_oxid_fdmi_rpa); > +} > + > static inline void fdls_schedule_tgt_oxid_free(struct fnic_iport_s *iport, > struct fnic_tgt_oxid_pool_s > *oxid_pool, uint16_t oxid) > @@ -406,6 +507,14 @@ static int fdls_is_oxid_in_fabric_range(uint16_t oxid) > (oxid_unmasked <= FDLS_FABRIC_OXID_POOL_END)); > } > > +static int fdls_is_oxid_in_fdmi_range(uint16_t oxid) > +{ > + uint16_t oxid_unmasked = FDLS_OXID_RSP_TYPE_UNMASKED(oxid); > + > + return ((oxid_unmasked >= FDLS_FDMI_OXID_POOL_BASE) && > + (oxid_unmasked <= FDLS_FDMI_OXID_POOL_END)); > +} > + > void fdls_init_tgt_oxid_pool(struct fnic_iport_s *iport) > { > memset(&iport->plogi_oxid_pool, 0, sizeof(iport->plogi_oxid_pool)); > @@ -671,6 +780,42 @@ static void fdls_send_fabric_abts(struct fnic_iport_s *iport) > iport->fabric.timer_pending = 1; > } > > +static void fdls_send_fdmi_abts(struct fnic_iport_s *iport) > +{ > + uint8_t fcid[3]; > + struct fc_frame_header fabric_abort = fc_std_fabric_abts; > + struct fc_frame_header *fabric_abts = &fabric_abort; > + struct fnic_fabric_oxid_pool_s *oxid_pool = &iport->fdmi_oxid_pool; > + int fdmi_tov; > + uint16_t oxid; > + > + hton24(fcid, 0XFFFFFA); > + > + if (iport->fabric.fdmi_pending & FDLS_FDMI_PLOGI_PENDING) { > + oxid = htons(oxid_pool->active_oxid_fdmi_plogi); > + FNIC_STD_SET_OX_ID(fabric_abts, oxid); > + fnic_send_fcoe_frame(iport, fabric_abts, > + sizeof(struct fc_frame_header)); > + } else { > + if (iport->fabric.fdmi_pending & FDLS_FDMI_REG_HBA_PENDING) { > + oxid = htons(oxid_pool->active_oxid_fdmi_rhba); > + FNIC_STD_SET_OX_ID(fabric_abts, oxid); > + fnic_send_fcoe_frame(iport, fabric_abts, > + sizeof(struct fc_frame_header)); > + } > + if (iport->fabric.fdmi_pending & FDLS_FDMI_RPA_PENDING) { > + oxid = htons(oxid_pool->active_oxid_fdmi_rpa); > + FNIC_STD_SET_OX_ID(fabric_abts, oxid); > + fnic_send_fcoe_frame(iport, fabric_abts, > + sizeof(struct fc_frame_header)); > + } > + } > + > + fdmi_tov = jiffies + msecs_to_jiffies(2 * iport->e_d_tov); > + mod_timer(&iport->fabric.fdmi_timer, round_jiffies(fdmi_tov)); > + iport->fabric.fdmi_pending |= FDLS_FDMI_ABORT_PENDING; > +} > + > static void fdls_send_fabric_flogi(struct fnic_iport_s *iport) > { > struct fc_std_flogi flogi; > @@ -738,6 +883,47 @@ static void fdls_send_fabric_plogi(struct fnic_iport_s *iport) > fdls_start_fabric_timer(iport, 2 * iport->e_d_tov); > } > > +static void fdls_send_fdmi_plogi(struct fnic_iport_s *iport) > +{ > + struct fc_std_flogi plogi; > + struct fc_frame_header *fchdr = &plogi.fchdr; > + uint8_t fcid[3]; > + struct fnic *fnic = iport->fnic; > + u64 fdmi_tov; > + uint16_t oxid; > + > + memcpy(&plogi, &fnic_std_plogi_req, sizeof(plogi)); Memcpy again. > + > + oxid = fdls_alloc_fabric_oxid(iport, &iport->fdmi_oxid_pool, > + FNIC_FDMI_PLOGI_RSP); > + if (oxid == 0xFFFF) { > + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, > + "Failed to allocate OXID to send fdmi plogi %p", > + iport); > + return; > + } > + > + hton24(fcid, iport->fcid); > + > + FNIC_STD_SET_S_ID(fchdr, fcid); > + hton24(fcid, 0XFFFFFA); > + FNIC_STD_SET_D_ID(fchdr, fcid); > + FNIC_STD_SET_OX_ID(fchdr, htons(oxid)); > + FNIC_LOGI_SET_NPORT_NAME(&plogi.els, iport->wwpn); > + FNIC_LOGI_SET_NODE_NAME(&plogi.els, iport->wwnn); > + FNIC_LOGI_SET_RDF_SIZE(&plogi.els, iport->max_payload_size); > + > + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, > + "fcid: 0x%x: FDLS send FDMI PLOGI with oxid:%x", > + iport->fcid, oxid); > + > + fnic_send_fcoe_frame(iport, &plogi, sizeof(struct fc_std_flogi)); > + > + fdmi_tov = jiffies + msecs_to_jiffies(2 * iport->e_d_tov); > + mod_timer(&iport->fabric.fdmi_timer, round_jiffies(fdmi_tov)); > + iport->fabric.fdmi_pending = FDLS_FDMI_PLOGI_PENDING; > +} > + > static void fdls_send_rpn_id(struct fnic_iport_s *iport) > { > struct fc_std_rpn_id rpn_id; > @@ -1375,6 +1561,126 @@ struct fnic_tport_s *fnic_find_tport_by_wwpn(struct fnic_iport_s *iport, > return NULL; > } > > +static void fdls_fdmi_register_hba(struct fnic_iport_s *iport) > +{ > + struct fc_std_fdmi_rhba fdmi_rhba; > + uint8_t fcid[3]; > + uint16_t len; > + int err; > + struct fnic *fnic = iport->fnic; > + struct vnic_devcmd_fw_info *fw_info = NULL; > + uint16_t oxid; > + > + memcpy(&fdmi_rhba, &fnic_std_fdmi_rhba, > + sizeof(struct fc_std_fdmi_rhba)); And here. > + > + hton24(fcid, iport->fcid); > + FNIC_STD_SET_S_ID((&fdmi_rhba.fchdr), fcid); > + > + oxid = fdls_alloc_fabric_oxid(iport, &iport->fdmi_oxid_pool, > + FNIC_FDMI_REG_HBA_RSP); > + if (oxid == 0xFFFF) { > + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, > + "Failed to allocate OXID to send fdmi reg hba %p", > + iport); > + return; > + } > + FNIC_STD_SET_OX_ID(&fdmi_rhba.fchdr, htons(oxid)); > + > + fdmi_rhba.hba_identifier = get_unaligned_be64(&iport->wwpn); > + fdmi_rhba.port_name = get_unaligned_be64(&iport->wwpn); > + fdmi_rhba.node_name = get_unaligned_be64(&iport->wwnn); > + > + err = vnic_dev_fw_info(fnic->vdev, &fw_info); > + if (!err) { > + snprintf(fdmi_rhba.serial_num, sizeof(fdmi_rhba.serial_num) - 1, > + "%s", fw_info->hw_serial_number); > + snprintf(fdmi_rhba.hardware_ver, > + sizeof(fdmi_rhba.hardware_ver) - 1, "%s", > + fw_info->hw_version); > + strscpy(fdmi_rhba.firmware_ver, fw_info->fw_version, > + sizeof(fdmi_rhba.firmware_ver) - 1); > + > + len = ARRAY_SIZE(fdmi_rhba.model); > + if (fnic->subsys_desc_len >= len) > + fnic->subsys_desc_len = len - 1; > + memcpy(&fdmi_rhba.model, fnic->subsys_desc, > + fnic->subsys_desc_len); > + fdmi_rhba.model[fnic->subsys_desc_len] = 0x00; > + } > + > + snprintf(fdmi_rhba.driver_ver, sizeof(fdmi_rhba.driver_ver) - 1, "%s", > + DRV_VERSION); > + snprintf(fdmi_rhba.rom_ver, sizeof(fdmi_rhba.rom_ver) - 1, "%s", "N/A"); > + > + fnic_send_fcoe_frame(iport, &fdmi_rhba, > + sizeof(struct fc_std_fdmi_rhba)); > + iport->fabric.fdmi_pending |= FDLS_FDMI_REG_HBA_PENDING; > +} > + > +static void fdls_fdmi_register_pa(struct fnic_iport_s *iport) > +{ > + struct fc_std_fdmi_rpa fdmi_rpa; > + > + uint8_t fcid[3]; > + struct fnic *fnic = iport->fnic; > + u32 port_speed_bm; > + u32 port_speed = vnic_dev_port_speed(fnic->vdev); > + uint16_t oxid; > + > + memcpy(&fdmi_rpa, &fnic_std_fdmi_rpa, sizeof(struct fc_std_fdmi_rpa)); And here. > + hton24(fcid, iport->fcid); > + FNIC_STD_SET_S_ID((&fdmi_rpa.fchdr), fcid); > + > + oxid = fdls_alloc_fabric_oxid(iport, &iport->fdmi_oxid_pool, > + FNIC_FDMI_RPA_RSP); > + if (oxid == 0xFFFF) { > + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, > + "Failed to allocate OXID to send fdmi rpa %p", > + iport); > + return; > + } > + FNIC_STD_SET_OX_ID(&fdmi_rpa.fchdr, htons(oxid)); > + > + fdmi_rpa.port_name = get_unaligned_be64(&iport->wwpn); > + > + /* MDS does not support GIGE speed. > + * Bit shift standard definitions from scsi_transport_fc.h to > + * match FC spec. > + */ > + switch (port_speed) { > + case DCEM_PORTSPEED_10G: > + case DCEM_PORTSPEED_20G: > + /* There is no bit for 20G */ > + port_speed_bm = FC_PORTSPEED_10GBIT << PORT_SPEED_BIT_14; > + break; > + case DCEM_PORTSPEED_25G: > + port_speed_bm = FC_PORTSPEED_25GBIT << PORT_SPEED_BIT_8; > + break; > + case DCEM_PORTSPEED_40G: > + case DCEM_PORTSPEED_4x10G: > + port_speed_bm = FC_PORTSPEED_40GBIT << PORT_SPEED_BIT_9; > + break; > + case DCEM_PORTSPEED_100G: > + port_speed_bm = FC_PORTSPEED_100GBIT << PORT_SPEED_BIT_8; > + break; > + default: > + port_speed_bm = FC_PORTSPEED_1GBIT << PORT_SPEED_BIT_15; > + break; > + } > + fdmi_rpa.supported_speed = htonl(port_speed_bm); > + fdmi_rpa.current_speed = htonl(port_speed_bm); > + fdmi_rpa.fc4_type[2] = 1; > + snprintf(fdmi_rpa.os_name, sizeof(fdmi_rpa.os_name) - 1, "host%d", > + fnic->lport->host->host_no); > + sprintf(fc_host_system_hostname(fnic->lport->host), "%s", utsname()->nodename); > + snprintf(fdmi_rpa.host_name, sizeof(fdmi_rpa.host_name) - 1, "%s", > + fc_host_system_hostname(fnic->lport->host)); > + > + fnic_send_fcoe_frame(iport, &fdmi_rpa, sizeof(struct fc_std_fdmi_rpa)); > + iport->fabric.fdmi_pending |= FDLS_FDMI_RPA_PENDING; > +} > + > void fdls_fabric_timer_callback(struct timer_list *t) > { > struct fnic_fdls_fabric_s *fabric = from_timer(fabric, t, retry_timer); > @@ -1548,6 +1854,43 @@ void fdls_fabric_timer_callback(struct timer_list *t) > spin_unlock_irqrestore(&fnic->fnic_lock, flags); > } > > +void fdls_fdmi_timer_callback(struct timer_list *t) > +{ > + struct fnic_fdls_fabric_s *fabric = from_timer(fabric, t, fdmi_timer); > + struct fnic_iport_s *iport = > + container_of(fabric, struct fnic_iport_s, fabric); > + struct fnic *fnic = iport->fnic; > + unsigned long flags; > + > + spin_lock_irqsave(&fnic->fnic_lock, flags); > + > + if (!iport->fabric.fdmi_pending) { > + /* timer expired after fdmi responses received. */ > + spin_unlock_irqrestore(&fnic->fnic_lock, flags); > + return; > + } > + > + /* if not abort pending, send an abort */ > + if (!(iport->fabric.fdmi_pending & FDLS_FDMI_ABORT_PENDING)) { > + fdls_send_fdmi_abts(iport); > + spin_unlock_irqrestore(&fnic->fnic_lock, flags); > + return; > + } > + > + /* Abort timed out */ > + fdls_schedule_fdmi_oxid_free(iport); > + > + iport->fabric.fdmi_pending = 0; > + /* If max retries not exhaused, start over from fdmi plogi */ > + if (iport->fabric.fdmi_retry < FDLS_FDMI_MAX_RETRY) { > + iport->fabric.fdmi_retry++; > + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, > + "retry fdmi timer %d", iport->fabric.fdmi_retry); > + fdls_send_fdmi_plogi(iport); > + } > + spin_unlock_irqrestore(&fnic->fnic_lock, flags); > +} > + > static void fdls_send_delete_tport_msg(struct fnic_tport_s *tport) > { > struct fnic_iport_s *iport = (struct fnic_iport_s *) tport->iport; > @@ -1697,6 +2040,15 @@ static void fnic_fdls_start_plogi(struct fnic_iport_s *iport) > fdls_send_fabric_plogi(iport); > fdls_set_state((&iport->fabric), FDLS_STATE_FABRIC_PLOGI); > iport->fabric.flags &= ~FNIC_FDLS_FABRIC_ABORT_ISSUED; > + > + if ((fnic_fdmi_support == 1) && (!(iport->flags & FNIC_FDMI_ACTIVE))) { > + /* we can do FDMI at the same time */ > + iport->fabric.fdmi_retry = 0; > + timer_setup(&iport->fabric.fdmi_timer, fdls_fdmi_timer_callback, > + 0); > + fdls_send_fdmi_plogi(iport); > + iport->flags |= FNIC_FDMI_ACTIVE; > + } > } > > static void > @@ -2784,6 +3136,109 @@ fdls_process_fabric_plogi_rsp(struct fnic_iport_s *iport, > } > } > > +static void fdls_process_fdmi_plogi_rsp(struct fnic_iport_s *iport, > + struct fc_frame_header *fchdr) > +{ > + struct fc_std_flogi *plogi_rsp = (struct fc_std_flogi *)fchdr; > + struct fc_std_els_rsp *els_rjt = (struct fc_std_els_rsp *)fchdr; > + struct fnic *fnic = iport->fnic; > + u64 fdmi_tov; > + > + iport->fabric.fdmi_pending &= ~FDLS_FDMI_PLOGI_PENDING; > + fdls_free_fabric_oxid(iport, &iport->fabric_oxid_pool, > + ntohs(FNIC_STD_GET_OX_ID(fchdr))); > + > + if (ntoh24(fchdr->fh_s_id) == 0XFFFFFA) { > + del_timer_sync(&iport->fabric.fdmi_timer); > + iport->fabric.fdmi_pending = 0; > + switch (plogi_rsp->els.fl_cmd) { > + case ELS_LS_ACC: > + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, > + "FDLS process fdmi PLOGI response status: ELS_LS_ACC\n"); > + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, > + "Sending fdmi registration for port 0x%x\n", > + iport->fcid); > + > + fdls_fdmi_register_hba(iport); > + fdls_fdmi_register_pa(iport); > + fdmi_tov = jiffies + msecs_to_jiffies(5000); > + mod_timer(&iport->fabric.fdmi_timer, > + round_jiffies(fdmi_tov)); > + break; > + case ELS_LS_RJT: > + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, > + "Fabric FDMI PLOGI returned ELS_LS_RJT reason: 0x%x", > + els_rjt->u.rej.er_reason); > + > + if (((els_rjt->u.rej.er_reason == ELS_RJT_BUSY) > + || (els_rjt->u.rej.er_reason == ELS_RJT_UNAB)) > + && (iport->fabric.fdmi_retry < 7)) { > + iport->fabric.fdmi_retry++; > + fdls_send_fdmi_plogi(iport); > + } > + break; > + default: > + break; > + } > + } > +} > + > +static void fdls_process_fdmi_reg_ack(struct fnic_iport_s *iport, > + struct fc_frame_header *fchdr, > + int rsp_type) > +{ > + struct fnic *fnic = iport->fnic; > + > + if (!iport->fabric.fdmi_pending) { > + FNIC_FCS_DBG(KERN_ERR, fnic->lport->host, fnic->fnic_num, > + "Received FDMI ack while not waiting:%x\n", > + ntohs(FNIC_STD_GET_OX_ID(fchdr))); > + return; > + } > + > + if (rsp_type == FNIC_FDMI_REG_HBA_RSP) > + iport->fabric.fdmi_pending &= ~FDLS_FDMI_REG_HBA_PENDING; > + else > + iport->fabric.fdmi_pending &= ~FDLS_FDMI_RPA_PENDING; > + > + fdls_free_fabric_oxid(iport, &iport->fdmi_oxid_pool, > + ntohs(FNIC_STD_GET_OX_ID(fchdr))); > + > + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, > + "iport fcid: 0x%x: Received FDMI registration ack\n", > + iport->fcid); > + > + if (!iport->fabric.fdmi_pending) { > + del_timer_sync(&iport->fabric.fdmi_timer); > + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, > + "iport fcid: 0x%x: Canceling FDMI timer\n", > + iport->fcid); > + } > +} > + > +static void fdls_process_fdmi_abts_rsp(struct fnic_iport_s *iport, > + struct fc_frame_header *fchdr) > +{ > + uint32_t s_id; > + struct fnic *fnic = iport->fnic; > + > + s_id = ntoh24(FNIC_STD_GET_S_ID(fchdr)); > + > + if (!(s_id != 0xFFFFFA)) { > + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, > + "Received abts rsp with invalid SID: 0x%x. Dropping frame", > + s_id); > + return; > + } > + > + del_timer_sync(&iport->fabric.fdmi_timer); > + iport->fabric.fdmi_pending &= ~FDLS_FDMI_ABORT_PENDING; > + > + fdls_free_fabric_oxid(iport, &iport->fdmi_oxid_pool, > + ntohs(FNIC_STD_GET_OX_ID(fchdr))); > + fdls_send_fdmi_plogi(iport); > +} > + > static void > fdls_process_fabric_abts_rsp(struct fnic_iport_s *iport, > struct fc_frame_header *fchdr) > @@ -3780,6 +4235,9 @@ fnic_fdls_validate_and_get_frame_type(struct fnic_iport_s *iport, > break; > > case FNIC_FABRIC_LOGO_RSP: > + case FNIC_FDMI_PLOGI_RSP: > + case FNIC_FDMI_REG_HBA_RSP: > + case FNIC_FDMI_RPA_RSP: > break; > default: > /* Drop the Rx frame and log/stats it */ > @@ -3822,6 +4280,9 @@ void fnic_fdls_recv_frame(struct fnic_iport_s *iport, void *rx_frame, > case FNIC_FABRIC_PLOGI_RSP: > fdls_process_fabric_plogi_rsp(iport, fchdr); > break; > + case FNIC_FDMI_PLOGI_RSP: > + fdls_process_fdmi_plogi_rsp(iport, fchdr); > + break; > case FNIC_FABRIC_RPN_RSP: > fdls_process_rpn_id_rsp(iport, fchdr); > break; > @@ -3861,6 +4322,9 @@ void fnic_fdls_recv_frame(struct fnic_iport_s *iport, void *rx_frame, > if (fdls_is_oxid_in_fabric_range(oxid) && > (iport->fabric.flags & FNIC_FDLS_FABRIC_ABORT_ISSUED)) { > fdls_process_fabric_abts_rsp(iport, fchdr); > + } else if (fdls_is_oxid_in_fdmi_range(oxid) && > + iport->fabric.fdmi_pending) { > + fdls_process_fdmi_abts_rsp(iport, fchdr); > } else { > fdls_process_tgt_abts_rsp(iport, fchdr); > } > @@ -3890,6 +4354,10 @@ void fnic_fdls_recv_frame(struct fnic_iport_s *iport, void *rx_frame, > case FNIC_ELS_RLS: > fdls_process_rls_req(iport, fchdr); > break; > + case FNIC_FDMI_REG_HBA_RSP: > + case FNIC_FDMI_RPA_RSP: > + fdls_process_fdmi_reg_ack(iport, fchdr, frame_type); > + break; > default: > FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, > "s_id: 0x%x d_did: 0x%x", s_id, d_id); > diff --git a/drivers/scsi/fnic/fnic.h b/drivers/scsi/fnic/fnic.h > index 92cd17efa40f..5d8315b24085 100644 > --- a/drivers/scsi/fnic/fnic.h > +++ b/drivers/scsi/fnic/fnic.h > @@ -82,6 +82,72 @@ > /* Retry supported by rport (returned by PRLI service parameters) */ > #define FNIC_FC_RP_FLAGS_RETRY 0x1 > > +/* Cisco vendor id */ > +#define PCI_VENDOR_ID_CISCO 0x1137 > +#define PCI_DEVICE_ID_CISCO_VIC_FC 0x0045 /* fc vnic */ > + > +/* sereno pcie switch */ > +#define PCI_DEVICE_ID_CISCO_SERENO 0x004e > +#define PCI_DEVICE_ID_CISCO_CRUZ 0x007a /* Cruz */ > +#define PCI_DEVICE_ID_CISCO_BODEGA 0x0131 /* Bodega */ > +#define PCI_DEVICE_ID_CISCO_BEVERLY 0x025f /* Beverly */ > + > +/* Sereno */ > +#define PCI_SUBDEVICE_ID_CISCO_VASONA 0x004f /* vasona mezz */ > +#define PCI_SUBDEVICE_ID_CISCO_COTATI 0x0084 /* cotati mlom */ > +#define PCI_SUBDEVICE_ID_CISCO_LEXINGTON 0x0085 /* lexington pcie */ > +#define PCI_SUBDEVICE_ID_CISCO_ICEHOUSE 0x00cd /* Icehouse */ > +#define PCI_SUBDEVICE_ID_CISCO_KIRKWOODLAKE 0x00ce /* KirkwoodLake pcie */ > +#define PCI_SUBDEVICE_ID_CISCO_SUSANVILLE 0x012e /* Susanville MLOM */ > +#define PCI_SUBDEVICE_ID_CISCO_TORRANCE 0x0139 /* Torrance MLOM */ > + > +/* Cruz */ > +#define PCI_SUBDEVICE_ID_CISCO_CALISTOGA 0x012c /* Calistoga MLOM */ > +#define PCI_SUBDEVICE_ID_CISCO_MOUNTAINVIEW 0x0137 /* Cruz Mezz */ > +/* Cruz MountTian SIOC */ > +#define PCI_SUBDEVICE_ID_CISCO_MOUNTTIAN 0x014b > +#define PCI_SUBDEVICE_ID_CISCO_CLEARLAKE 0x014d /* ClearLake pcie */ > +/* Cruz MountTian2 SIOC */ > +#define PCI_SUBDEVICE_ID_CISCO_MOUNTTIAN2 0x0157 > +#define PCI_SUBDEVICE_ID_CISCO_CLAREMONT 0x015d /* Claremont MLOM */ > + > +/* Bodega */ > +/* VIC 1457 PCIe mLOM */ > +#define PCI_SUBDEVICE_ID_CISCO_BRADBURY 0x0218 > +#define PCI_SUBDEVICE_ID_CISCO_BRENTWOOD 0x0217 /* VIC 1455 PCIe */ > +/* VIC 1487 PCIe mLOM */ > +#define PCI_SUBDEVICE_ID_CISCO_BURLINGAME 0x021a > +#define PCI_SUBDEVICE_ID_CISCO_BAYSIDE 0x0219 /* VIC 1485 PCIe */ > +/* VIC 1440 Mezz mLOM */ > +#define PCI_SUBDEVICE_ID_CISCO_BAKERSFIELD 0x0215 > +#define PCI_SUBDEVICE_ID_CISCO_BOONVILLE 0x0216 /* VIC 1480 Mezz */ > +#define PCI_SUBDEVICE_ID_CISCO_BENICIA 0x024a /* VIC 1495 */ > +#define PCI_SUBDEVICE_ID_CISCO_BEAUMONT 0x024b /* VIC 1497 */ > +#define PCI_SUBDEVICE_ID_CISCO_BRISBANE 0x02af /* VIC 1467 */ > +#define PCI_SUBDEVICE_ID_CISCO_BENTON 0x02b0 /* VIC 1477 */ > +#define PCI_SUBDEVICE_ID_CISCO_TWIN_RIVER 0x02cf /* VIC 14425 */ > +#define PCI_SUBDEVICE_ID_CISCO_TWIN_PEAK 0x02d0 /* VIC 14825 */ > + > +/* Beverly */ > +#define PCI_SUBDEVICE_ID_CISCO_BERN 0x02de /* VIC 15420 */ > +#define PCI_SUBDEVICE_ID_CISCO_STOCKHOLM 0x02dd /* VIC 15428 */ > +#define PCI_SUBDEVICE_ID_CISCO_KRAKOW 0x02dc /* VIC 15411 */ > +#define PCI_SUBDEVICE_ID_CISCO_LUCERNE 0x02db /* VIC 15231 */ > +#define PCI_SUBDEVICE_ID_CISCO_TURKU 0x02e8 /* VIC 15238 */ > +#define PCI_SUBDEVICE_ID_CISCO_TURKU_PLUS 0x02f3 /* VIC 15237 */ > +#define PCI_SUBDEVICE_ID_CISCO_ZURICH 0x02df /* VIC 15230 */ > +#define PCI_SUBDEVICE_ID_CISCO_RIGA 0x02e0 /* VIC 15427 */ > +#define PCI_SUBDEVICE_ID_CISCO_GENEVA 0x02e1 /* VIC 15422 */ > +#define PCI_SUBDEVICE_ID_CISCO_HELSINKI 0x02e4 /* VIC 15235 */ > +#define PCI_SUBDEVICE_ID_CISCO_GOTHENBURG 0x02f2 /* VIC 15425 */ > + > +struct fnic_pcie_device { > + u32 device; > + u8 *desc; > + u32 subsystem_device; > + u8 *subsys_desc; > +}; > + Not sure what this has to do with FDMI ... maybe move to a separate patch? > /* > * fnic private data per SCSI command. > * These fields are locked by the hashed io_req_lock. > @@ -134,6 +200,7 @@ static inline u64 fnic_flags_and_state(struct scsi_cmnd *cmd) > #define fnic_clear_state_flags(fnicp, st_flags) \ > __fnic_set_state_flags(fnicp, st_flags, 1) > > +extern unsigned int fnic_fdmi_support; > extern unsigned int fnic_log_level; > extern unsigned int io_completions; > extern struct workqueue_struct *fnic_event_queue; > @@ -336,6 +403,9 @@ struct fnic { > struct work_struct tport_work; > struct list_head tport_event_list; > > + char subsys_desc[14]; > + int subsys_desc_len; > + > /*** FIP related data members -- start ***/ > void (*set_vlan)(struct fnic *, u16 vlan); > struct work_struct fip_frame_work; > @@ -433,5 +503,7 @@ fnic_chk_state_flags_locked(struct fnic *fnic, unsigned long st_flags) > void __fnic_set_state_flags(struct fnic *, unsigned long, unsigned long); > void fnic_dump_fchost_stats(struct Scsi_Host *, struct fc_host_statistics *); > void fnic_free_txq(struct list_head *head); > +int fnic_get_desc_by_devid(struct pci_dev *pdev, char **desc, > + char **subsys_desc); > > #endif /* _FNIC_H_ */ > diff --git a/drivers/scsi/fnic/fnic_main.c b/drivers/scsi/fnic/fnic_main.c > index 16c9f87c932b..c8d2fcf5d948 100644 > --- a/drivers/scsi/fnic/fnic_main.c > +++ b/drivers/scsi/fnic/fnic_main.c > @@ -62,6 +62,9 @@ unsigned int fnic_log_level; > module_param(fnic_log_level, int, S_IRUGO|S_IWUSR); > MODULE_PARM_DESC(fnic_log_level, "bit mask of fnic logging levels"); > > +unsigned int fnic_fdmi_support = 1; > +module_param(fnic_fdmi_support, int, 0644); > +MODULE_PARM_DESC(fnic_fdmi_support, "FDMI support"); > > unsigned int io_completions = FNIC_DFLT_IO_COMPLETIONS; > module_param(io_completions, int, S_IRUGO|S_IWUSR); > @@ -607,6 +610,8 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) > int i; > unsigned long flags; > int hwq; > + char *desc, *subsys_desc; > + int len; > > /* > * Allocate SCSI Host and set up association between host, > @@ -640,6 +645,23 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) > fnic->fnic_num = fnic_id; > fnic_stats_debugfs_init(fnic); > > + /* Find model name from PCIe subsys ID */ > + if (fnic_get_desc_by_devid(pdev, &desc, &subsys_desc) == 0) { > + dev_info(&fnic->pdev->dev, "Model: %s\n", subsys_desc); > + > + /* Update FDMI model */ > + fnic->subsys_desc_len = strlen(subsys_desc); > + len = ARRAY_SIZE(fnic->subsys_desc); > + if (fnic->subsys_desc_len > len) > + fnic->subsys_desc_len = len; > + memcpy(fnic->subsys_desc, subsys_desc, fnic->subsys_desc_len); > + dev_info(&fnic->pdev->dev, "FDMI Model: %s\n", fnic->subsys_desc); > + } else { > + fnic->subsys_desc_len = 0; > + dev_info(&fnic->pdev->dev, "Model: %s subsys_id: 0x%04x\n", "Unknown", > + pdev->subsystem_device); > + } > + > err = pci_enable_device(pdev); > if (err) { > dev_err(&fnic->pdev->dev, "Cannot enable PCI device, aborting.\n"); > @@ -1014,6 +1036,9 @@ static void fnic_remove(struct pci_dev *pdev) > fnic_fcoe_evlist_free(fnic); > } > > + if ((fnic_fdmi_support == 1) && (fnic->iport.fabric.fdmi_pending > 0)) > + del_timer_sync(&fnic->iport.fabric.fdmi_timer); > + > /* > * Log off the fabric. This stops all remote ports, dns port, > * logs off the fabric. This flushes all rport, disc, lport work > diff --git a/drivers/scsi/fnic/fnic_pci_subsys_devid.c b/drivers/scsi/fnic/fnic_pci_subsys_devid.c > new file mode 100644 > index 000000000000..36a2c1268422 > --- /dev/null > +++ b/drivers/scsi/fnic/fnic_pci_subsys_devid.c > @@ -0,0 +1,131 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +/* > + * Copyright 2008 Cisco Systems, Inc. All rights reserved. > + * Copyright 2007 Nuova Systems, Inc. All rights reserved. > + */ > + > +#include <linux/module.h> > +#include <linux/mempool.h> > +#include <linux/string.h> > +#include <linux/slab.h> > +#include <linux/errno.h> > +#include <linux/init.h> > +#include <linux/pci.h> > +#include <linux/interrupt.h> > +#include <linux/irq.h> > +#include <linux/spinlock.h> > +#include <linux/workqueue.h> > +#include <linux/kthread.h> > +#include <linux/if_ether.h> > +#include "fnic.h" > + > +static struct fnic_pcie_device fnic_pcie_device_table[] = { > + {PCI_DEVICE_ID_CISCO_SERENO, "Sereno", PCI_SUBDEVICE_ID_CISCO_VASONA, > + "VIC 1280"}, > + {PCI_DEVICE_ID_CISCO_SERENO, "Sereno", PCI_SUBDEVICE_ID_CISCO_COTATI, > + "VIC 1240"}, > + {PCI_DEVICE_ID_CISCO_SERENO, "Sereno", > + PCI_SUBDEVICE_ID_CISCO_LEXINGTON, "VIC 1225"}, > + {PCI_DEVICE_ID_CISCO_SERENO, "Sereno", PCI_SUBDEVICE_ID_CISCO_ICEHOUSE, > + "VIC 1285"}, > + {PCI_DEVICE_ID_CISCO_SERENO, "Sereno", > + PCI_SUBDEVICE_ID_CISCO_KIRKWOODLAKE, "VIC 1225T"}, > + {PCI_DEVICE_ID_CISCO_SERENO, "Sereno", > + PCI_SUBDEVICE_ID_CISCO_SUSANVILLE, "VIC 1227"}, > + {PCI_DEVICE_ID_CISCO_SERENO, "Sereno", PCI_SUBDEVICE_ID_CISCO_TORRANCE, > + "VIC 1227T"}, > + > + {PCI_DEVICE_ID_CISCO_CRUZ, "Cruz", PCI_SUBDEVICE_ID_CISCO_CALISTOGA, > + "VIC 1340"}, > + {PCI_DEVICE_ID_CISCO_CRUZ, "Cruz", PCI_SUBDEVICE_ID_CISCO_MOUNTAINVIEW, > + "VIC 1380"}, > + {PCI_DEVICE_ID_CISCO_CRUZ, "Cruz", PCI_SUBDEVICE_ID_CISCO_MOUNTTIAN, > + "C3260-SIOC"}, > + {PCI_DEVICE_ID_CISCO_CRUZ, "Cruz", PCI_SUBDEVICE_ID_CISCO_CLEARLAKE, > + "VIC 1385"}, > + {PCI_DEVICE_ID_CISCO_CRUZ, "Cruz", PCI_SUBDEVICE_ID_CISCO_MOUNTTIAN2, > + "C3260-SIOC"}, > + {PCI_DEVICE_ID_CISCO_CRUZ, "Cruz", PCI_SUBDEVICE_ID_CISCO_CLAREMONT, > + "VIC 1387"}, > + > + {PCI_DEVICE_ID_CISCO_BODEGA, "Bodega", PCI_SUBDEVICE_ID_CISCO_BRADBURY, > + "VIC 1457"}, > + {PCI_DEVICE_ID_CISCO_BODEGA, "Bodega", > + PCI_SUBDEVICE_ID_CISCO_BRENTWOOD, "VIC 1455"}, > + {PCI_DEVICE_ID_CISCO_BODEGA, "Bodega", > + PCI_SUBDEVICE_ID_CISCO_BURLINGAME, "VIC 1487"}, > + {PCI_DEVICE_ID_CISCO_BODEGA, "Bodega", PCI_SUBDEVICE_ID_CISCO_BAYSIDE, > + "VIC 1485"}, > + {PCI_DEVICE_ID_CISCO_BODEGA, "Bodega", > + PCI_SUBDEVICE_ID_CISCO_BAKERSFIELD, "VIC 1440"}, > + {PCI_DEVICE_ID_CISCO_BODEGA, "Bodega", > + PCI_SUBDEVICE_ID_CISCO_BOONVILLE, "VIC 1480"}, > + {PCI_DEVICE_ID_CISCO_BODEGA, "Bodega", PCI_SUBDEVICE_ID_CISCO_BENICIA, > + "VIC 1495"}, > + {PCI_DEVICE_ID_CISCO_BODEGA, "Bodega", PCI_SUBDEVICE_ID_CISCO_BEAUMONT, > + "VIC 1497"}, > + {PCI_DEVICE_ID_CISCO_BODEGA, "Bodega", PCI_SUBDEVICE_ID_CISCO_BRISBANE, > + "VIC 1467"}, > + {PCI_DEVICE_ID_CISCO_BODEGA, "Bodega", PCI_SUBDEVICE_ID_CISCO_BENTON, > + "VIC 1477"}, > + {PCI_DEVICE_ID_CISCO_BODEGA, "Bodega", > + PCI_SUBDEVICE_ID_CISCO_TWIN_RIVER, "VIC 14425"}, > + {PCI_DEVICE_ID_CISCO_BODEGA, "Bodega", > + PCI_SUBDEVICE_ID_CISCO_TWIN_PEAK, "VIC 14825"}, > + > + {PCI_DEVICE_ID_CISCO_BEVERLY, "Beverly", PCI_SUBDEVICE_ID_CISCO_BERN, > + "VIC 15420"}, > + {PCI_DEVICE_ID_CISCO_BEVERLY, "Beverly", > + PCI_SUBDEVICE_ID_CISCO_STOCKHOLM, "VIC 15428"}, > + {PCI_DEVICE_ID_CISCO_BEVERLY, "Beverly", PCI_SUBDEVICE_ID_CISCO_KRAKOW, > + "VIC 15411"}, > + {PCI_DEVICE_ID_CISCO_BEVERLY, "Beverly", > + PCI_SUBDEVICE_ID_CISCO_LUCERNE, "VIC 15231"}, > + {PCI_DEVICE_ID_CISCO_BEVERLY, "Beverly", PCI_SUBDEVICE_ID_CISCO_TURKU, > + "VIC 15238"}, > + {PCI_DEVICE_ID_CISCO_BEVERLY, "Beverly", PCI_SUBDEVICE_ID_CISCO_GENEVA, > + "VIC 15422"}, > + {PCI_DEVICE_ID_CISCO_BEVERLY, "Beverly", > + PCI_SUBDEVICE_ID_CISCO_HELSINKI, "VIC 15235"}, > + {PCI_DEVICE_ID_CISCO_BEVERLY, "Beverly", > + PCI_SUBDEVICE_ID_CISCO_GOTHENBURG, "VIC 15425"}, > + {PCI_DEVICE_ID_CISCO_BEVERLY, "Beverly", > + PCI_SUBDEVICE_ID_CISCO_TURKU_PLUS, "VIC 15237"}, > + {PCI_DEVICE_ID_CISCO_BEVERLY, "Beverly", PCI_SUBDEVICE_ID_CISCO_ZURICH, > + "VIC 15230"}, > + {PCI_DEVICE_ID_CISCO_BEVERLY, "Beverly", PCI_SUBDEVICE_ID_CISCO_RIGA, > + "VIC 15427"}, > + > + {0,} > +}; > + > +int fnic_get_desc_by_devid(struct pci_dev *pdev, char **desc, > + char **subsys_desc) > +{ > + unsigned short device = PCI_DEVICE_ID_CISCO_VIC_FC; > + int max = ARRAY_SIZE(fnic_pcie_device_table); > + struct fnic_pcie_device *t = fnic_pcie_device_table; > + int index = 0; > + > + if (pdev->device != device) > + return 1; > + > + while (t->device != 0) { > + if (memcmp > + ((char *) &pdev->subsystem_device, > + (char *) &t->subsystem_device, sizeof(short)) == 0) > + break; > + t++; > + index++; > + } > + > + if (index >= max - 1) { > + *desc = NULL; > + *subsys_desc = NULL; > + return 1; > + } > + > + *desc = fnic_pcie_device_table[index].desc; > + *subsys_desc = fnic_pcie_device_table[index].subsys_desc; > + return 0; > +} Same here. Maybe move the PCI registration stuff to a different patch. Cheers, Hannes
On Thursday, October 24, 2024 12:33 AM, Hannes Reinecke <hare@suse.de> wrote: > > On 10/18/24 18:14, Karan Tilak Kumar wrote: > > Add support for Fabric-Device Management Interface > > (FDMI) by introducing PCI device IDs for Cisco > > Hardware. > > Introduce a module parameter to enable/disable > > FDMI support. > > Integrate support for FDMI. > > > > Reported-by: kernel test robot <lkp@intel.com> > > Closes: > > https://lore.kernel.org/oe-kbuild-all/202406110734.p2v8dq9v-lkp > > @intel.com/ > > > > Reviewed-by: Sesidhar Baddela <sebaddel@cisco.com> > > Co-developed-by: Gian Carlo Boffa <gcboffa@cisco.com> > > Signed-off-by: Gian Carlo Boffa <gcboffa@cisco.com> > > Co-developed-by: Arulprabhu Ponnusamy <arulponn@cisco.com> > > Signed-off-by: Arulprabhu Ponnusamy <arulponn@cisco.com> > > Co-developed-by: Arun Easi <aeasi@cisco.com> > > Signed-off-by: Arun Easi <aeasi@cisco.com> > > Co-developed-by: Karan Tilak Kumar <kartilak@cisco.com> > > Signed-off-by: Karan Tilak Kumar <kartilak@cisco.com> > > --- > > Changes between v4 and v5: > > Incorporate review comments from Martin: > > Modify attribution appropriately. > > Remove spurious newline at the end of fdls_disc.c. > > Remove spurious newline at the end of fnic_main.c. > > > > Changes between v2 and v3: > > Incorporate review comments from Hannes: > > Replace redundant definitions with standard definitions. > > > > Changes between v1 and v2: > > Incorporate review comments from Hannes from other patches: > > Replace pr_info with dev_info. > > Replace htonll() with get_unaligned_be64(). > > Replace definitions with standard definitions from fc_els.h. > > Use standard definitions from scsi_transport_fc.h for > > port speeds. > > Refactor definitions in struct fnic to avoid cache holes. > > Replace memcmp with not equal to operator. > > Fix warning from kernel test robot: > > Remove version.h > > --- > > drivers/scsi/fnic/Makefile | 3 +- > > drivers/scsi/fnic/fdls_disc.c | 468 ++++++++++++++++++++++ > > drivers/scsi/fnic/fnic.h | 72 ++++ > > drivers/scsi/fnic/fnic_main.c | 25 ++ > > drivers/scsi/fnic/fnic_pci_subsys_devid.c | 131 ++++++ > > 5 files changed, 698 insertions(+), 1 deletion(-) > > create mode 100644 drivers/scsi/fnic/fnic_pci_subsys_devid.c > > > > diff --git a/drivers/scsi/fnic/Makefile b/drivers/scsi/fnic/Makefile > > index 3bd6b1c8b643..af156c69da0c 100644 > > --- a/drivers/scsi/fnic/Makefile > > +++ b/drivers/scsi/fnic/Makefile > > @@ -16,4 +16,5 @@ fnic-y := \ > > vnic_intr.o \ > > vnic_rq.o \ > > vnic_wq_copy.o \ > > - vnic_wq.o > > + vnic_wq.o \ > > + fnic_pci_subsys_devid.o > > diff --git a/drivers/scsi/fnic/fdls_disc.c b/drivers/scsi/fnic/fdls_disc.c > > index a9a98ddc3a84..0b1d69ff19df 100644 > > --- a/drivers/scsi/fnic/fdls_disc.c > > +++ b/drivers/scsi/fnic/fdls_disc.c > > @@ -9,11 +9,23 @@ > > #include "fdls_fc.h" > > #include "fnic_fdls.h" > > #include <scsi/fc/fc_fcp.h> > > +#include <scsi/scsi_transport_fc.h> > > #include <linux/utsname.h> > > > > #define FC_FC4_TYPE_SCSI 0x08 > > +#define PORT_SPEED_BIT_8 8 > > +#define PORT_SPEED_BIT_9 9 > > +#define PORT_SPEED_BIT_14 14 > > +#define PORT_SPEED_BIT_15 15 > > > > static void fdls_send_rpn_id(struct fnic_iport_s *iport); > > +static void fdls_fdmi_register_hba(struct fnic_iport_s *iport); > > +static void fdls_fdmi_register_pa(struct fnic_iport_s *iport); > > +#define FDLS_FDMI_PLOGI_PENDING 0x1 > > +#define FDLS_FDMI_REG_HBA_PENDING 0x2 > > +#define FDLS_FDMI_RPA_PENDING 0x4 > > +#define FDLS_FDMI_ABORT_PENDING 0x8 > > +#define FDLS_FDMI_MAX_RETRY 3 > > > > /* Frame initialization */ > > /* > > @@ -84,6 +96,70 @@ struct fc_std_els_prli fnic_std_prli_req = { > > .spp_params = cpu_to_be32(0xA2)} > > }; > > > > +/* > > + * Variables: > > + * sid, port_id, port_name > > + */ > > +struct fc_std_fdmi_rhba fnic_std_fdmi_rhba = { > > + .fchdr = {.fh_r_ctl = FC_RCTL_DD_UNSOL_CTL, > > + .fh_d_id = {0xFF, 0XFF, 0XFA}, > > + .fh_type = FC_TYPE_CT, .fh_f_ctl = {FNIC_ELS_REQ_FCTL, 0, 0}, > > + .fh_rx_id = 0xFFFF}, > > + .fc_std_ct_hdr = {.ct_rev = FC_CT_REV, .ct_fs_type = FC_FST_MGMT, > > + .ct_fs_subtype = FC_FDMI_SUBTYPE, > > + .ct_cmd = cpu_to_be16(FC_FDMI_RHBA)}, > > + .num_ports = FNIC_FDMI_NUM_PORTS, > > + .num_hba_attributes = FNIC_FDMI_NUM_HBA_ATTRS, > > + .type_nn = FNIC_FDMI_TYPE_NODE_NAME, > > + .length_nn = FNIC_FDMI_NN_LEN, > > + .type_manu = FNIC_FDMI_TYPE_MANUFACTURER, > > + .length_manu = FNIC_FDMI_MANU_LEN, > > + .manufacturer = FNIC_FDMI_MANUFACTURER, > > + .type_serial = FNIC_FDMI_TYPE_SERIAL_NUMBER, > > + .length_serial = FNIC_FDMI_SERIAL_LEN, > > + .type_model = FNIC_FDMI_TYPE_MODEL, > > + .length_model = FNIC_FDMI_MODEL_LEN, > > + .type_model_des = FNIC_FDMI_TYPE_MODEL_DES, > > + .length_model_des = FNIC_FDMI_MODEL_DES_LEN, > > + .model_description = FNIC_FDMI_MODEL_DESCRIPTION, > > + .type_hw_ver = FNIC_FDMI_TYPE_HARDWARE_VERSION, > > + .length_hw_ver = FNIC_FDMI_HW_VER_LEN, > > + .type_dr_ver = FNIC_FDMI_TYPE_DRIVER_VERSION, > > + .length_dr_ver = FNIC_FDMI_DR_VER_LEN, > > + .type_rom_ver = FNIC_FDMI_TYPE_ROM_VERSION, > > + .length_rom_ver = FNIC_FDMI_ROM_VER_LEN, > > + .type_fw_ver = FNIC_FDMI_TYPE_FIRMWARE_VERSION, > > + .length_fw_ver = FNIC_FDMI_FW_VER_LEN, > > +}; > > + > > +/* > > + * Variables > > + *sid, port_id, port_name > > + */ > > +struct fc_std_fdmi_rpa fnic_std_fdmi_rpa = { > > + .fchdr = {.fh_r_ctl = FC_RCTL_DD_UNSOL_CTL, > > + .fh_d_id = {0xFF, 0xFF, 0xFA}, > > + .fh_type = FC_TYPE_CT, .fh_f_ctl = {FNIC_ELS_REQ_FCTL, 0, 0}, > > + .fh_rx_id = 0xFFFF}, > > + .fc_std_ct_hdr = {.ct_rev = FC_CT_REV, .ct_fs_type = FC_FST_MGMT, > > + .ct_fs_subtype = FC_FDMI_SUBTYPE, > > + .ct_cmd = cpu_to_be16(FC_FDMI_RPA)}, > > + .num_port_attributes = FNIC_FDMI_NUM_PORT_ATTRS, > > + .type_fc4 = FNIC_FDMI_TYPE_FC4_TYPES, > > + .length_fc4 = FNIC_FDMI_FC4_LEN, > > + .type_supp_speed = FNIC_FDMI_TYPE_SUPPORTED_SPEEDS, > > + .length_supp_speed = FNIC_FDMI_SUPP_SPEED_LEN, > > + .type_cur_speed = FNIC_FDMI_TYPE_CURRENT_SPEED, > > + .length_cur_speed = FNIC_FDMI_CUR_SPEED_LEN, > > + .type_max_frame_size = FNIC_FDMI_TYPE_MAX_FRAME_SIZE, > > + .length_max_frame_size = FNIC_FDMI_MFS_LEN, > > + .max_frame_size = FNIC_FDMI_MFS, > > + .type_os_name = FNIC_FDMI_TYPE_OS_NAME, > > + .length_os_name = FNIC_FDMI_OS_NAME_LEN, > > + .type_host_name = FNIC_FDMI_TYPE_HOST_NAME, > > + .length_host_name = FNIC_FDMI_HN_LEN, > > +}; > > + > > /* > > * Variables: > > * fh_s_id, port_id, port_name > > @@ -224,6 +300,7 @@ static void fdls_target_restart_nexus(struct fnic_tport_s *tport); > > static void fdls_start_tport_timer(struct fnic_iport_s *iport, > > struct fnic_tport_s *tport, int timeout); > > static void fdls_tport_timer_callback(struct timer_list *t); > > +static void fdls_send_fdmi_plogi(struct fnic_iport_s *iport); > > static void fdls_start_fabric_timer(struct fnic_iport_s *iport, > > int timeout); > > static void > > @@ -337,6 +414,15 @@ uint16_t fdls_alloc_fabric_oxid(struct fnic_iport_s *iport, > > * separately. > > */ > > switch (exp_rsp_type) { > > + case FNIC_FDMI_PLOGI_RSP: > > + oxid_pool->active_oxid_fdmi_plogi = oxid; > > + break; > > + case FNIC_FDMI_REG_HBA_RSP: > > + oxid_pool->active_oxid_fdmi_rhba = oxid; > > + break; > > + case FNIC_FDMI_RPA_RSP: > > + oxid_pool->active_oxid_fdmi_rpa = oxid; > > + break; > > default: > > oxid_pool->active_oxid_fabric_req = oxid; > > break; > > @@ -372,6 +458,21 @@ static inline void fdls_schedule_fabric_oxid_free(struct fnic_iport_s > > iport->fabric_oxid_pool.active_oxid_fabric_req); > > } > > > > +static inline void fdls_schedule_fdmi_oxid_free(struct fnic_iport_s *iport) > > +{ > > + if (iport->fabric.fdmi_pending & FDLS_FDMI_PLOGI_PENDING) > > + fdls_schedule_oxid_free(&iport->fdmi_oxid_pool.meta, > > + iport->fdmi_oxid_pool.active_oxid_fdmi_plogi); > > + > > + if (iport->fabric.fdmi_pending & FDLS_FDMI_REG_HBA_PENDING) > > + fdls_schedule_oxid_free(&iport->fdmi_oxid_pool.meta, > > + iport->fdmi_oxid_pool.active_oxid_fdmi_rhba); > > + > > + if (iport->fabric.fdmi_pending & FDLS_FDMI_RPA_PENDING) > > + fdls_schedule_oxid_free(&iport->fdmi_oxid_pool.meta, > > + iport->fdmi_oxid_pool.active_oxid_fdmi_rpa); > > +} > > + > > static inline void fdls_schedule_tgt_oxid_free(struct fnic_iport_s *iport, > > struct fnic_tgt_oxid_pool_s > > *oxid_pool, uint16_t oxid) > > @@ -406,6 +507,14 @@ static int fdls_is_oxid_in_fabric_range(uint16_t oxid) > > (oxid_unmasked <= FDLS_FABRIC_OXID_POOL_END)); > > } > > > > +static int fdls_is_oxid_in_fdmi_range(uint16_t oxid) > > +{ > > + uint16_t oxid_unmasked = FDLS_OXID_RSP_TYPE_UNMASKED(oxid); > > + > > + return ((oxid_unmasked >= FDLS_FDMI_OXID_POOL_BASE) && > > + (oxid_unmasked <= FDLS_FDMI_OXID_POOL_END)); > > +} > > + > > void fdls_init_tgt_oxid_pool(struct fnic_iport_s *iport) > > { > > memset(&iport->plogi_oxid_pool, 0, sizeof(iport->plogi_oxid_pool)); > > @@ -671,6 +780,42 @@ static void fdls_send_fabric_abts(struct fnic_iport_s *iport) > > iport->fabric.timer_pending = 1; > > } > > > > +static void fdls_send_fdmi_abts(struct fnic_iport_s *iport) > > +{ > > + uint8_t fcid[3]; > > + struct fc_frame_header fabric_abort = fc_std_fabric_abts; > > + struct fc_frame_header *fabric_abts = &fabric_abort; > > + struct fnic_fabric_oxid_pool_s *oxid_pool = &iport->fdmi_oxid_pool; > > + int fdmi_tov; > > + uint16_t oxid; > > + > > + hton24(fcid, 0XFFFFFA); > > + > > + if (iport->fabric.fdmi_pending & FDLS_FDMI_PLOGI_PENDING) { > > + oxid = htons(oxid_pool->active_oxid_fdmi_plogi); > > + FNIC_STD_SET_OX_ID(fabric_abts, oxid); > > + fnic_send_fcoe_frame(iport, fabric_abts, > > + sizeof(struct fc_frame_header)); > > + } else { > > + if (iport->fabric.fdmi_pending & FDLS_FDMI_REG_HBA_PENDING) { > > + oxid = htons(oxid_pool->active_oxid_fdmi_rhba); > > + FNIC_STD_SET_OX_ID(fabric_abts, oxid); > > + fnic_send_fcoe_frame(iport, fabric_abts, > > + sizeof(struct fc_frame_header)); > > + } > > + if (iport->fabric.fdmi_pending & FDLS_FDMI_RPA_PENDING) { > > + oxid = htons(oxid_pool->active_oxid_fdmi_rpa); > > + FNIC_STD_SET_OX_ID(fabric_abts, oxid); > > + fnic_send_fcoe_frame(iport, fabric_abts, > > + sizeof(struct fc_frame_header)); > > + } > > + } > > + > > + fdmi_tov = jiffies + msecs_to_jiffies(2 * iport->e_d_tov); > > + mod_timer(&iport->fabric.fdmi_timer, round_jiffies(fdmi_tov)); > > + iport->fabric.fdmi_pending |= FDLS_FDMI_ABORT_PENDING; > > +} > > + > > static void fdls_send_fabric_flogi(struct fnic_iport_s *iport) > > { > > struct fc_std_flogi flogi; > > @@ -738,6 +883,47 @@ static void fdls_send_fabric_plogi(struct fnic_iport_s *iport) > > fdls_start_fabric_timer(iport, 2 * iport->e_d_tov); > > } > > > > +static void fdls_send_fdmi_plogi(struct fnic_iport_s *iport) > > +{ > > + struct fc_std_flogi plogi; > > + struct fc_frame_header *fchdr = &plogi.fchdr; > > + uint8_t fcid[3]; > > + struct fnic *fnic = iport->fnic; > > + u64 fdmi_tov; > > + uint16_t oxid; > > + > > + memcpy(&plogi, &fnic_std_plogi_req, sizeof(plogi)); > Memcpy again. Thanks Hannes. I'll fix it in the next version of changes. > > + > > + oxid = fdls_alloc_fabric_oxid(iport, &iport->fdmi_oxid_pool, > > + FNIC_FDMI_PLOGI_RSP); > > + if (oxid == 0xFFFF) { > > + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, > > + "Failed to allocate OXID to send fdmi plogi %p", > > + iport); > > + return; > > + } > > + > > + hton24(fcid, iport->fcid); > > + > > + FNIC_STD_SET_S_ID(fchdr, fcid); > > + hton24(fcid, 0XFFFFFA); > > + FNIC_STD_SET_D_ID(fchdr, fcid); > > + FNIC_STD_SET_OX_ID(fchdr, htons(oxid)); > > + FNIC_LOGI_SET_NPORT_NAME(&plogi.els, iport->wwpn); > > + FNIC_LOGI_SET_NODE_NAME(&plogi.els, iport->wwnn); > > + FNIC_LOGI_SET_RDF_SIZE(&plogi.els, iport->max_payload_size); > > + > > + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, > > + "fcid: 0x%x: FDLS send FDMI PLOGI with oxid:%x", > > + iport->fcid, oxid); > > + > > + fnic_send_fcoe_frame(iport, &plogi, sizeof(struct fc_std_flogi)); > > + > > + fdmi_tov = jiffies + msecs_to_jiffies(2 * iport->e_d_tov); > > + mod_timer(&iport->fabric.fdmi_timer, round_jiffies(fdmi_tov)); > > + iport->fabric.fdmi_pending = FDLS_FDMI_PLOGI_PENDING; > > +} > > + > > static void fdls_send_rpn_id(struct fnic_iport_s *iport) > > { > > struct fc_std_rpn_id rpn_id; > > @@ -1375,6 +1561,126 @@ struct fnic_tport_s *fnic_find_tport_by_wwpn(struct fnic_iport_s *iport, > > return NULL; > > } > > > > +static void fdls_fdmi_register_hba(struct fnic_iport_s *iport) > > +{ > > + struct fc_std_fdmi_rhba fdmi_rhba; > > + uint8_t fcid[3]; > > + uint16_t len; > > + int err; > > + struct fnic *fnic = iport->fnic; > > + struct vnic_devcmd_fw_info *fw_info = NULL; > > + uint16_t oxid; > > + > > + memcpy(&fdmi_rhba, &fnic_std_fdmi_rhba, > > + sizeof(struct fc_std_fdmi_rhba)); > And here. Thanks Hannes. I'll fix it in the next version of changes. > > + > > + hton24(fcid, iport->fcid); > > + FNIC_STD_SET_S_ID((&fdmi_rhba.fchdr), fcid); > > + > > + oxid = fdls_alloc_fabric_oxid(iport, &iport->fdmi_oxid_pool, > > + FNIC_FDMI_REG_HBA_RSP); > > + if (oxid == 0xFFFF) { > > + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, > > + "Failed to allocate OXID to send fdmi reg hba %p", > > + iport); > > + return; > > + } > > + FNIC_STD_SET_OX_ID(&fdmi_rhba.fchdr, htons(oxid)); > > + > > + fdmi_rhba.hba_identifier = get_unaligned_be64(&iport->wwpn); > > + fdmi_rhba.port_name = get_unaligned_be64(&iport->wwpn); > > + fdmi_rhba.node_name = get_unaligned_be64(&iport->wwnn); > > + > > + err = vnic_dev_fw_info(fnic->vdev, &fw_info); > > + if (!err) { > > + snprintf(fdmi_rhba.serial_num, sizeof(fdmi_rhba.serial_num) - 1, > > + "%s", fw_info->hw_serial_number); > > + snprintf(fdmi_rhba.hardware_ver, > > + sizeof(fdmi_rhba.hardware_ver) - 1, "%s", > > + fw_info->hw_version); > > + strscpy(fdmi_rhba.firmware_ver, fw_info->fw_version, > > + sizeof(fdmi_rhba.firmware_ver) - 1); > > + > > + len = ARRAY_SIZE(fdmi_rhba.model); > > + if (fnic->subsys_desc_len >= len) > > + fnic->subsys_desc_len = len - 1; > > + memcpy(&fdmi_rhba.model, fnic->subsys_desc, > > + fnic->subsys_desc_len); > > + fdmi_rhba.model[fnic->subsys_desc_len] = 0x00; > > + } > > + > > + snprintf(fdmi_rhba.driver_ver, sizeof(fdmi_rhba.driver_ver) - 1, "%s", > > + DRV_VERSION); > > + snprintf(fdmi_rhba.rom_ver, sizeof(fdmi_rhba.rom_ver) - 1, "%s", "N/A"); > > + > > + fnic_send_fcoe_frame(iport, &fdmi_rhba, > > + sizeof(struct fc_std_fdmi_rhba)); > > + iport->fabric.fdmi_pending |= FDLS_FDMI_REG_HBA_PENDING; > > +} > > + > > +static void fdls_fdmi_register_pa(struct fnic_iport_s *iport) > > +{ > > + struct fc_std_fdmi_rpa fdmi_rpa; > > + > > + uint8_t fcid[3]; > > + struct fnic *fnic = iport->fnic; > > + u32 port_speed_bm; > > + u32 port_speed = vnic_dev_port_speed(fnic->vdev); > > + uint16_t oxid; > > + > > + memcpy(&fdmi_rpa, &fnic_std_fdmi_rpa, sizeof(struct fc_std_fdmi_rpa)); > And here. Thanks Hannes. I'll fix it in the next version of changes. > > + hton24(fcid, iport->fcid); > > + FNIC_STD_SET_S_ID((&fdmi_rpa.fchdr), fcid); > > + > > + oxid = fdls_alloc_fabric_oxid(iport, &iport->fdmi_oxid_pool, > > + FNIC_FDMI_RPA_RSP); > > + if (oxid == 0xFFFF) { > > + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, > > + "Failed to allocate OXID to send fdmi rpa %p", > > + iport); > > + return; > > + } > > + FNIC_STD_SET_OX_ID(&fdmi_rpa.fchdr, htons(oxid)); > > + > > + fdmi_rpa.port_name = get_unaligned_be64(&iport->wwpn); > > + > > + /* MDS does not support GIGE speed. > > + * Bit shift standard definitions from scsi_transport_fc.h to > > + * match FC spec. > > + */ > > + switch (port_speed) { > > + case DCEM_PORTSPEED_10G: > > + case DCEM_PORTSPEED_20G: > > + /* There is no bit for 20G */ > > + port_speed_bm = FC_PORTSPEED_10GBIT << PORT_SPEED_BIT_14; > > + break; > > + case DCEM_PORTSPEED_25G: > > + port_speed_bm = FC_PORTSPEED_25GBIT << PORT_SPEED_BIT_8; > > + break; > > + case DCEM_PORTSPEED_40G: > > + case DCEM_PORTSPEED_4x10G: > > + port_speed_bm = FC_PORTSPEED_40GBIT << PORT_SPEED_BIT_9; > > + break; > > + case DCEM_PORTSPEED_100G: > > + port_speed_bm = FC_PORTSPEED_100GBIT << PORT_SPEED_BIT_8; > > + break; > > + default: > > + port_speed_bm = FC_PORTSPEED_1GBIT << PORT_SPEED_BIT_15; > > + break; > > + } > > + fdmi_rpa.supported_speed = htonl(port_speed_bm); > > + fdmi_rpa.current_speed = htonl(port_speed_bm); > > + fdmi_rpa.fc4_type[2] = 1; > > + snprintf(fdmi_rpa.os_name, sizeof(fdmi_rpa.os_name) - 1, "host%d", > > + fnic->lport->host->host_no); > > + sprintf(fc_host_system_hostname(fnic->lport->host), "%s", utsname()->nodename); > > + snprintf(fdmi_rpa.host_name, sizeof(fdmi_rpa.host_name) - 1, "%s", > > + fc_host_system_hostname(fnic->lport->host)); > > + > > + fnic_send_fcoe_frame(iport, &fdmi_rpa, sizeof(struct fc_std_fdmi_rpa)); > > + iport->fabric.fdmi_pending |= FDLS_FDMI_RPA_PENDING; > > +} > > + > > void fdls_fabric_timer_callback(struct timer_list *t) > > { > > struct fnic_fdls_fabric_s *fabric = from_timer(fabric, t, retry_timer); > > @@ -1548,6 +1854,43 @@ void fdls_fabric_timer_callback(struct timer_list *t) > > spin_unlock_irqrestore(&fnic->fnic_lock, flags); > > } > > > > +void fdls_fdmi_timer_callback(struct timer_list *t) > > +{ > > + struct fnic_fdls_fabric_s *fabric = from_timer(fabric, t, fdmi_timer); > > + struct fnic_iport_s *iport = > > + container_of(fabric, struct fnic_iport_s, fabric); > > + struct fnic *fnic = iport->fnic; > > + unsigned long flags; > > + > > + spin_lock_irqsave(&fnic->fnic_lock, flags); > > + > > + if (!iport->fabric.fdmi_pending) { > > + /* timer expired after fdmi responses received. */ > > + spin_unlock_irqrestore(&fnic->fnic_lock, flags); > > + return; > > + } > > + > > + /* if not abort pending, send an abort */ > > + if (!(iport->fabric.fdmi_pending & FDLS_FDMI_ABORT_PENDING)) { > > + fdls_send_fdmi_abts(iport); > > + spin_unlock_irqrestore(&fnic->fnic_lock, flags); > > + return; > > + } > > + > > + /* Abort timed out */ > > + fdls_schedule_fdmi_oxid_free(iport); > > + > > + iport->fabric.fdmi_pending = 0; > > + /* If max retries not exhaused, start over from fdmi plogi */ > > + if (iport->fabric.fdmi_retry < FDLS_FDMI_MAX_RETRY) { > > + iport->fabric.fdmi_retry++; > > + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, > > + "retry fdmi timer %d", iport->fabric.fdmi_retry); > > + fdls_send_fdmi_plogi(iport); > > + } > > + spin_unlock_irqrestore(&fnic->fnic_lock, flags); > > +} > > + > > static void fdls_send_delete_tport_msg(struct fnic_tport_s *tport) > > { > > struct fnic_iport_s *iport = (struct fnic_iport_s *) tport->iport; > > @@ -1697,6 +2040,15 @@ static void fnic_fdls_start_plogi(struct fnic_iport_s *iport) > > fdls_send_fabric_plogi(iport); > > fdls_set_state((&iport->fabric), FDLS_STATE_FABRIC_PLOGI); > > iport->fabric.flags &= ~FNIC_FDLS_FABRIC_ABORT_ISSUED; > > + > > + if ((fnic_fdmi_support == 1) && (!(iport->flags & FNIC_FDMI_ACTIVE))) { > > + /* we can do FDMI at the same time */ > > + iport->fabric.fdmi_retry = 0; > > + timer_setup(&iport->fabric.fdmi_timer, fdls_fdmi_timer_callback, > > + 0); > > + fdls_send_fdmi_plogi(iport); > > + iport->flags |= FNIC_FDMI_ACTIVE; > > + } > > } > > > > static void > > @@ -2784,6 +3136,109 @@ fdls_process_fabric_plogi_rsp(struct fnic_iport_s *iport, > > } > > } > > > > +static void fdls_process_fdmi_plogi_rsp(struct fnic_iport_s *iport, > > + struct fc_frame_header *fchdr) > > +{ > > + struct fc_std_flogi *plogi_rsp = (struct fc_std_flogi *)fchdr; > > + struct fc_std_els_rsp *els_rjt = (struct fc_std_els_rsp *)fchdr; > > + struct fnic *fnic = iport->fnic; > > + u64 fdmi_tov; > > + > > + iport->fabric.fdmi_pending &= ~FDLS_FDMI_PLOGI_PENDING; > > + fdls_free_fabric_oxid(iport, &iport->fabric_oxid_pool, > > + ntohs(FNIC_STD_GET_OX_ID(fchdr))); > > + > > + if (ntoh24(fchdr->fh_s_id) == 0XFFFFFA) { > > + del_timer_sync(&iport->fabric.fdmi_timer); > > + iport->fabric.fdmi_pending = 0; > > + switch (plogi_rsp->els.fl_cmd) { > > + case ELS_LS_ACC: > > + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, > > + "FDLS process fdmi PLOGI response status: ELS_LS_ACC\n"); > > + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, > > + "Sending fdmi registration for port 0x%x\n", > > + iport->fcid); > > + > > + fdls_fdmi_register_hba(iport); > > + fdls_fdmi_register_pa(iport); > > + fdmi_tov = jiffies + msecs_to_jiffies(5000); > > + mod_timer(&iport->fabric.fdmi_timer, > > + round_jiffies(fdmi_tov)); > > + break; > > + case ELS_LS_RJT: > > + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, > > + "Fabric FDMI PLOGI returned ELS_LS_RJT reason: 0x%x", > > + els_rjt->u.rej.er_reason); > > + > > + if (((els_rjt->u.rej.er_reason == ELS_RJT_BUSY) > > + || (els_rjt->u.rej.er_reason == ELS_RJT_UNAB)) > > + && (iport->fabric.fdmi_retry < 7)) { > > + iport->fabric.fdmi_retry++; > > + fdls_send_fdmi_plogi(iport); > > + } > > + break; > > + default: > > + break; > > + } > > + } > > +} > > + > > +static void fdls_process_fdmi_reg_ack(struct fnic_iport_s *iport, > > + struct fc_frame_header *fchdr, > > + int rsp_type) > > +{ > > + struct fnic *fnic = iport->fnic; > > + > > + if (!iport->fabric.fdmi_pending) { > > + FNIC_FCS_DBG(KERN_ERR, fnic->lport->host, fnic->fnic_num, > > + "Received FDMI ack while not waiting:%x\n", > > + ntohs(FNIC_STD_GET_OX_ID(fchdr))); > > + return; > > + } > > + > > + if (rsp_type == FNIC_FDMI_REG_HBA_RSP) > > + iport->fabric.fdmi_pending &= ~FDLS_FDMI_REG_HBA_PENDING; > > + else > > + iport->fabric.fdmi_pending &= ~FDLS_FDMI_RPA_PENDING; > > + > > + fdls_free_fabric_oxid(iport, &iport->fdmi_oxid_pool, > > + ntohs(FNIC_STD_GET_OX_ID(fchdr))); > > + > > + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, > > + "iport fcid: 0x%x: Received FDMI registration ack\n", > > + iport->fcid); > > + > > + if (!iport->fabric.fdmi_pending) { > > + del_timer_sync(&iport->fabric.fdmi_timer); > > + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, > > + "iport fcid: 0x%x: Canceling FDMI timer\n", > > + iport->fcid); > > + } > > +} > > + > > +static void fdls_process_fdmi_abts_rsp(struct fnic_iport_s *iport, > > + struct fc_frame_header *fchdr) > > +{ > > + uint32_t s_id; > > + struct fnic *fnic = iport->fnic; > > + > > + s_id = ntoh24(FNIC_STD_GET_S_ID(fchdr)); > > + > > + if (!(s_id != 0xFFFFFA)) { > > + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, > > + "Received abts rsp with invalid SID: 0x%x. Dropping frame", > > + s_id); > > + return; > > + } > > + > > + del_timer_sync(&iport->fabric.fdmi_timer); > > + iport->fabric.fdmi_pending &= ~FDLS_FDMI_ABORT_PENDING; > > + > > + fdls_free_fabric_oxid(iport, &iport->fdmi_oxid_pool, > > + ntohs(FNIC_STD_GET_OX_ID(fchdr))); > > + fdls_send_fdmi_plogi(iport); > > +} > > + > > static void > > fdls_process_fabric_abts_rsp(struct fnic_iport_s *iport, > > struct fc_frame_header *fchdr) > > @@ -3780,6 +4235,9 @@ fnic_fdls_validate_and_get_frame_type(struct fnic_iport_s *iport, > > break; > > > > case FNIC_FABRIC_LOGO_RSP: > > + case FNIC_FDMI_PLOGI_RSP: > > + case FNIC_FDMI_REG_HBA_RSP: > > + case FNIC_FDMI_RPA_RSP: > > break; > > default: > > /* Drop the Rx frame and log/stats it */ > > @@ -3822,6 +4280,9 @@ void fnic_fdls_recv_frame(struct fnic_iport_s *iport, void *rx_frame, > > case FNIC_FABRIC_PLOGI_RSP: > > fdls_process_fabric_plogi_rsp(iport, fchdr); > > break; > > + case FNIC_FDMI_PLOGI_RSP: > > + fdls_process_fdmi_plogi_rsp(iport, fchdr); > > + break; > > case FNIC_FABRIC_RPN_RSP: > > fdls_process_rpn_id_rsp(iport, fchdr); > > break; > > @@ -3861,6 +4322,9 @@ void fnic_fdls_recv_frame(struct fnic_iport_s *iport, void *rx_frame, > > if (fdls_is_oxid_in_fabric_range(oxid) && > > (iport->fabric.flags & FNIC_FDLS_FABRIC_ABORT_ISSUED)) { > > fdls_process_fabric_abts_rsp(iport, fchdr); > > + } else if (fdls_is_oxid_in_fdmi_range(oxid) && > > + iport->fabric.fdmi_pending) { > > + fdls_process_fdmi_abts_rsp(iport, fchdr); > > } else { > > fdls_process_tgt_abts_rsp(iport, fchdr); > > } > > @@ -3890,6 +4354,10 @@ void fnic_fdls_recv_frame(struct fnic_iport_s *iport, void *rx_frame, > > case FNIC_ELS_RLS: > > fdls_process_rls_req(iport, fchdr); > > break; > > + case FNIC_FDMI_REG_HBA_RSP: > > + case FNIC_FDMI_RPA_RSP: > > + fdls_process_fdmi_reg_ack(iport, fchdr, frame_type); > > + break; > > default: > > FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, > > "s_id: 0x%x d_did: 0x%x", s_id, d_id); > > diff --git a/drivers/scsi/fnic/fnic.h b/drivers/scsi/fnic/fnic.h > > index 92cd17efa40f..5d8315b24085 100644 > > --- a/drivers/scsi/fnic/fnic.h > > +++ b/drivers/scsi/fnic/fnic.h > > @@ -82,6 +82,72 @@ > > /* Retry supported by rport (returned by PRLI service parameters) */ > > #define FNIC_FC_RP_FLAGS_RETRY 0x1 > > > > +/* Cisco vendor id */ > > +#define PCI_VENDOR_ID_CISCO 0x1137 > > +#define PCI_DEVICE_ID_CISCO_VIC_FC 0x0045 /* fc vnic */ > > + > > +/* sereno pcie switch */ > > +#define PCI_DEVICE_ID_CISCO_SERENO 0x004e > > +#define PCI_DEVICE_ID_CISCO_CRUZ 0x007a /* Cruz */ > > +#define PCI_DEVICE_ID_CISCO_BODEGA 0x0131 /* Bodega */ > > +#define PCI_DEVICE_ID_CISCO_BEVERLY 0x025f /* Beverly */ > > + > > +/* Sereno */ > > +#define PCI_SUBDEVICE_ID_CISCO_VASONA 0x004f /* vasona mezz */ > > +#define PCI_SUBDEVICE_ID_CISCO_COTATI 0x0084 /* cotati mlom */ > > +#define PCI_SUBDEVICE_ID_CISCO_LEXINGTON 0x0085 /* lexington pcie */ > > +#define PCI_SUBDEVICE_ID_CISCO_ICEHOUSE 0x00cd /* Icehouse */ > > +#define PCI_SUBDEVICE_ID_CISCO_KIRKWOODLAKE 0x00ce /* KirkwoodLake pcie */ > > +#define PCI_SUBDEVICE_ID_CISCO_SUSANVILLE 0x012e /* Susanville MLOM */ > > +#define PCI_SUBDEVICE_ID_CISCO_TORRANCE 0x0139 /* Torrance MLOM */ > > + > > +/* Cruz */ > > +#define PCI_SUBDEVICE_ID_CISCO_CALISTOGA 0x012c /* Calistoga MLOM */ > > +#define PCI_SUBDEVICE_ID_CISCO_MOUNTAINVIEW 0x0137 /* Cruz Mezz */ > > +/* Cruz MountTian SIOC */ > > +#define PCI_SUBDEVICE_ID_CISCO_MOUNTTIAN 0x014b > > +#define PCI_SUBDEVICE_ID_CISCO_CLEARLAKE 0x014d /* ClearLake pcie */ > > +/* Cruz MountTian2 SIOC */ > > +#define PCI_SUBDEVICE_ID_CISCO_MOUNTTIAN2 0x0157 > > +#define PCI_SUBDEVICE_ID_CISCO_CLAREMONT 0x015d /* Claremont MLOM */ > > + > > +/* Bodega */ > > +/* VIC 1457 PCIe mLOM */ > > +#define PCI_SUBDEVICE_ID_CISCO_BRADBURY 0x0218 > > +#define PCI_SUBDEVICE_ID_CISCO_BRENTWOOD 0x0217 /* VIC 1455 PCIe */ > > +/* VIC 1487 PCIe mLOM */ > > +#define PCI_SUBDEVICE_ID_CISCO_BURLINGAME 0x021a > > +#define PCI_SUBDEVICE_ID_CISCO_BAYSIDE 0x0219 /* VIC 1485 PCIe */ > > +/* VIC 1440 Mezz mLOM */ > > +#define PCI_SUBDEVICE_ID_CISCO_BAKERSFIELD 0x0215 > > +#define PCI_SUBDEVICE_ID_CISCO_BOONVILLE 0x0216 /* VIC 1480 Mezz */ > > +#define PCI_SUBDEVICE_ID_CISCO_BENICIA 0x024a /* VIC 1495 */ > > +#define PCI_SUBDEVICE_ID_CISCO_BEAUMONT 0x024b /* VIC 1497 */ > > +#define PCI_SUBDEVICE_ID_CISCO_BRISBANE 0x02af /* VIC 1467 */ > > +#define PCI_SUBDEVICE_ID_CISCO_BENTON 0x02b0 /* VIC 1477 */ > > +#define PCI_SUBDEVICE_ID_CISCO_TWIN_RIVER 0x02cf /* VIC 14425 */ > > +#define PCI_SUBDEVICE_ID_CISCO_TWIN_PEAK 0x02d0 /* VIC 14825 */ > > + > > +/* Beverly */ > > +#define PCI_SUBDEVICE_ID_CISCO_BERN 0x02de /* VIC 15420 */ > > +#define PCI_SUBDEVICE_ID_CISCO_STOCKHOLM 0x02dd /* VIC 15428 */ > > +#define PCI_SUBDEVICE_ID_CISCO_KRAKOW 0x02dc /* VIC 15411 */ > > +#define PCI_SUBDEVICE_ID_CISCO_LUCERNE 0x02db /* VIC 15231 */ > > +#define PCI_SUBDEVICE_ID_CISCO_TURKU 0x02e8 /* VIC 15238 */ > > +#define PCI_SUBDEVICE_ID_CISCO_TURKU_PLUS 0x02f3 /* VIC 15237 */ > > +#define PCI_SUBDEVICE_ID_CISCO_ZURICH 0x02df /* VIC 15230 */ > > +#define PCI_SUBDEVICE_ID_CISCO_RIGA 0x02e0 /* VIC 15427 */ > > +#define PCI_SUBDEVICE_ID_CISCO_GENEVA 0x02e1 /* VIC 15422 */ > > +#define PCI_SUBDEVICE_ID_CISCO_HELSINKI 0x02e4 /* VIC 15235 */ > > +#define PCI_SUBDEVICE_ID_CISCO_GOTHENBURG 0x02f2 /* VIC 15425 */ > > + > > +struct fnic_pcie_device { > > + u32 device; > > + u8 *desc; > > + u32 subsystem_device; > > + u8 *subsys_desc; > > +}; > > + > > Not sure what this has to do with FDMI ... maybe move to a separate patch? The fnic driver updates the FDMI model in fnic_probe using this information. That's why I combined this set of changes in this patch. But sure, I can move it to a different patch. > > /* > > * fnic private data per SCSI command. > > * These fields are locked by the hashed io_req_lock. > > @@ -134,6 +200,7 @@ static inline u64 fnic_flags_and_state(struct scsi_cmnd *cmd) > > #define fnic_clear_state_flags(fnicp, st_flags) \ > > __fnic_set_state_flags(fnicp, st_flags, 1) > > > > +extern unsigned int fnic_fdmi_support; > > extern unsigned int fnic_log_level; > > extern unsigned int io_completions; > > extern struct workqueue_struct *fnic_event_queue; > > @@ -336,6 +403,9 @@ struct fnic { > > struct work_struct tport_work; > > struct list_head tport_event_list; > > > > + char subsys_desc[14]; > > + int subsys_desc_len; > > + > > /*** FIP related data members -- start ***/ > > void (*set_vlan)(struct fnic *, u16 vlan); > > struct work_struct fip_frame_work; > > @@ -433,5 +503,7 @@ fnic_chk_state_flags_locked(struct fnic *fnic, unsigned long st_flags) > > void __fnic_set_state_flags(struct fnic *, unsigned long, unsigned long); > > void fnic_dump_fchost_stats(struct Scsi_Host *, struct fc_host_statistics *); > > void fnic_free_txq(struct list_head *head); > > +int fnic_get_desc_by_devid(struct pci_dev *pdev, char **desc, > > + char **subsys_desc); > > > > #endif /* _FNIC_H_ */ > > diff --git a/drivers/scsi/fnic/fnic_main.c b/drivers/scsi/fnic/fnic_main.c > > index 16c9f87c932b..c8d2fcf5d948 100644 > > --- a/drivers/scsi/fnic/fnic_main.c > > +++ b/drivers/scsi/fnic/fnic_main.c > > @@ -62,6 +62,9 @@ unsigned int fnic_log_level; > > module_param(fnic_log_level, int, S_IRUGO|S_IWUSR); > > MODULE_PARM_DESC(fnic_log_level, "bit mask of fnic logging levels"); > > > > +unsigned int fnic_fdmi_support = 1; > > +module_param(fnic_fdmi_support, int, 0644); > > +MODULE_PARM_DESC(fnic_fdmi_support, "FDMI support"); > > > > unsigned int io_completions = FNIC_DFLT_IO_COMPLETIONS; > > module_param(io_completions, int, S_IRUGO|S_IWUSR); > > @@ -607,6 +610,8 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) > > int i; > > unsigned long flags; > > int hwq; > > + char *desc, *subsys_desc; > > + int len; > > > > /* > > * Allocate SCSI Host and set up association between host, > > @@ -640,6 +645,23 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) > > fnic->fnic_num = fnic_id; > > fnic_stats_debugfs_init(fnic); > > > > + /* Find model name from PCIe subsys ID */ > > + if (fnic_get_desc_by_devid(pdev, &desc, &subsys_desc) == 0) { > > + dev_info(&fnic->pdev->dev, "Model: %s\n", subsys_desc); > > + > > + /* Update FDMI model */ > > + fnic->subsys_desc_len = strlen(subsys_desc); > > + len = ARRAY_SIZE(fnic->subsys_desc); > > + if (fnic->subsys_desc_len > len) > > + fnic->subsys_desc_len = len; > > + memcpy(fnic->subsys_desc, subsys_desc, fnic->subsys_desc_len); > > + dev_info(&fnic->pdev->dev, "FDMI Model: %s\n", fnic->subsys_desc); > > + } else { > > + fnic->subsys_desc_len = 0; > > + dev_info(&fnic->pdev->dev, "Model: %s subsys_id: 0x%04x\n", "Unknown", > > + pdev->subsystem_device); > > + } > > + > > err = pci_enable_device(pdev); > > if (err) { > > dev_err(&fnic->pdev->dev, "Cannot enable PCI device, aborting.\n"); > > @@ -1014,6 +1036,9 @@ static void fnic_remove(struct pci_dev *pdev) > > fnic_fcoe_evlist_free(fnic); > > } > > > > + if ((fnic_fdmi_support == 1) && (fnic->iport.fabric.fdmi_pending > 0)) > > + del_timer_sync(&fnic->iport.fabric.fdmi_timer); > > + > > /* > > * Log off the fabric. This stops all remote ports, dns port, > > * logs off the fabric. This flushes all rport, disc, lport work > > diff --git a/drivers/scsi/fnic/fnic_pci_subsys_devid.c b/drivers/scsi/fnic/fnic_pci_subsys_devid.c > > new file mode 100644 > > index 000000000000..36a2c1268422 > > --- /dev/null > > +++ b/drivers/scsi/fnic/fnic_pci_subsys_devid.c > > @@ -0,0 +1,131 @@ > > +// SPDX-License-Identifier: GPL-2.0-only > > +/* > > + * Copyright 2008 Cisco Systems, Inc. All rights reserved. > > + * Copyright 2007 Nuova Systems, Inc. All rights reserved. > > + */ > > + > > +#include <linux/module.h> > > +#include <linux/mempool.h> > > +#include <linux/string.h> > > +#include <linux/slab.h> > > +#include <linux/errno.h> > > +#include <linux/init.h> > > +#include <linux/pci.h> > > +#include <linux/interrupt.h> > > +#include <linux/irq.h> > > +#include <linux/spinlock.h> > > +#include <linux/workqueue.h> > > +#include <linux/kthread.h> > > +#include <linux/if_ether.h> > > +#include "fnic.h" > > + > > +static struct fnic_pcie_device fnic_pcie_device_table[] = { > > + {PCI_DEVICE_ID_CISCO_SERENO, "Sereno", PCI_SUBDEVICE_ID_CISCO_VASONA, > > + "VIC 1280"}, > > + {PCI_DEVICE_ID_CISCO_SERENO, "Sereno", PCI_SUBDEVICE_ID_CISCO_COTATI, > > + "VIC 1240"}, > > + {PCI_DEVICE_ID_CISCO_SERENO, "Sereno", > > + PCI_SUBDEVICE_ID_CISCO_LEXINGTON, "VIC 1225"}, > > + {PCI_DEVICE_ID_CISCO_SERENO, "Sereno", PCI_SUBDEVICE_ID_CISCO_ICEHOUSE, > > + "VIC 1285"}, > > + {PCI_DEVICE_ID_CISCO_SERENO, "Sereno", > > + PCI_SUBDEVICE_ID_CISCO_KIRKWOODLAKE, "VIC 1225T"}, > > + {PCI_DEVICE_ID_CISCO_SERENO, "Sereno", > > + PCI_SUBDEVICE_ID_CISCO_SUSANVILLE, "VIC 1227"}, > > + {PCI_DEVICE_ID_CISCO_SERENO, "Sereno", PCI_SUBDEVICE_ID_CISCO_TORRANCE, > > + "VIC 1227T"}, > > + > > + {PCI_DEVICE_ID_CISCO_CRUZ, "Cruz", PCI_SUBDEVICE_ID_CISCO_CALISTOGA, > > + "VIC 1340"}, > > + {PCI_DEVICE_ID_CISCO_CRUZ, "Cruz", PCI_SUBDEVICE_ID_CISCO_MOUNTAINVIEW, > > + "VIC 1380"}, > > + {PCI_DEVICE_ID_CISCO_CRUZ, "Cruz", PCI_SUBDEVICE_ID_CISCO_MOUNTTIAN, > > + "C3260-SIOC"}, > > + {PCI_DEVICE_ID_CISCO_CRUZ, "Cruz", PCI_SUBDEVICE_ID_CISCO_CLEARLAKE, > > + "VIC 1385"}, > > + {PCI_DEVICE_ID_CISCO_CRUZ, "Cruz", PCI_SUBDEVICE_ID_CISCO_MOUNTTIAN2, > > + "C3260-SIOC"}, > > + {PCI_DEVICE_ID_CISCO_CRUZ, "Cruz", PCI_SUBDEVICE_ID_CISCO_CLAREMONT, > > + "VIC 1387"}, > > + > > + {PCI_DEVICE_ID_CISCO_BODEGA, "Bodega", PCI_SUBDEVICE_ID_CISCO_BRADBURY, > > + "VIC 1457"}, > > + {PCI_DEVICE_ID_CISCO_BODEGA, "Bodega", > > + PCI_SUBDEVICE_ID_CISCO_BRENTWOOD, "VIC 1455"}, > > + {PCI_DEVICE_ID_CISCO_BODEGA, "Bodega", > > + PCI_SUBDEVICE_ID_CISCO_BURLINGAME, "VIC 1487"}, > > + {PCI_DEVICE_ID_CISCO_BODEGA, "Bodega", PCI_SUBDEVICE_ID_CISCO_BAYSIDE, > > + "VIC 1485"}, > > + {PCI_DEVICE_ID_CISCO_BODEGA, "Bodega", > > + PCI_SUBDEVICE_ID_CISCO_BAKERSFIELD, "VIC 1440"}, > > + {PCI_DEVICE_ID_CISCO_BODEGA, "Bodega", > > + PCI_SUBDEVICE_ID_CISCO_BOONVILLE, "VIC 1480"}, > > + {PCI_DEVICE_ID_CISCO_BODEGA, "Bodega", PCI_SUBDEVICE_ID_CISCO_BENICIA, > > + "VIC 1495"}, > > + {PCI_DEVICE_ID_CISCO_BODEGA, "Bodega", PCI_SUBDEVICE_ID_CISCO_BEAUMONT, > > + "VIC 1497"}, > > + {PCI_DEVICE_ID_CISCO_BODEGA, "Bodega", PCI_SUBDEVICE_ID_CISCO_BRISBANE, > > + "VIC 1467"}, > > + {PCI_DEVICE_ID_CISCO_BODEGA, "Bodega", PCI_SUBDEVICE_ID_CISCO_BENTON, > > + "VIC 1477"}, > > + {PCI_DEVICE_ID_CISCO_BODEGA, "Bodega", > > + PCI_SUBDEVICE_ID_CISCO_TWIN_RIVER, "VIC 14425"}, > > + {PCI_DEVICE_ID_CISCO_BODEGA, "Bodega", > > + PCI_SUBDEVICE_ID_CISCO_TWIN_PEAK, "VIC 14825"}, > > + > > + {PCI_DEVICE_ID_CISCO_BEVERLY, "Beverly", PCI_SUBDEVICE_ID_CISCO_BERN, > > + "VIC 15420"}, > > + {PCI_DEVICE_ID_CISCO_BEVERLY, "Beverly", > > + PCI_SUBDEVICE_ID_CISCO_STOCKHOLM, "VIC 15428"}, > > + {PCI_DEVICE_ID_CISCO_BEVERLY, "Beverly", PCI_SUBDEVICE_ID_CISCO_KRAKOW, > > + "VIC 15411"}, > > + {PCI_DEVICE_ID_CISCO_BEVERLY, "Beverly", > > + PCI_SUBDEVICE_ID_CISCO_LUCERNE, "VIC 15231"}, > > + {PCI_DEVICE_ID_CISCO_BEVERLY, "Beverly", PCI_SUBDEVICE_ID_CISCO_TURKU, > > + "VIC 15238"}, > > + {PCI_DEVICE_ID_CISCO_BEVERLY, "Beverly", PCI_SUBDEVICE_ID_CISCO_GENEVA, > > + "VIC 15422"}, > > + {PCI_DEVICE_ID_CISCO_BEVERLY, "Beverly", > > + PCI_SUBDEVICE_ID_CISCO_HELSINKI, "VIC 15235"}, > > + {PCI_DEVICE_ID_CISCO_BEVERLY, "Beverly", > > + PCI_SUBDEVICE_ID_CISCO_GOTHENBURG, "VIC 15425"}, > > + {PCI_DEVICE_ID_CISCO_BEVERLY, "Beverly", > > + PCI_SUBDEVICE_ID_CISCO_TURKU_PLUS, "VIC 15237"}, > > + {PCI_DEVICE_ID_CISCO_BEVERLY, "Beverly", PCI_SUBDEVICE_ID_CISCO_ZURICH, > > + "VIC 15230"}, > > + {PCI_DEVICE_ID_CISCO_BEVERLY, "Beverly", PCI_SUBDEVICE_ID_CISCO_RIGA, > > + "VIC 15427"}, > > + > > + {0,} > > +}; > > + > > +int fnic_get_desc_by_devid(struct pci_dev *pdev, char **desc, > > + char **subsys_desc) > > +{ > > + unsigned short device = PCI_DEVICE_ID_CISCO_VIC_FC; > > + int max = ARRAY_SIZE(fnic_pcie_device_table); > > + struct fnic_pcie_device *t = fnic_pcie_device_table; > > + int index = 0; > > + > > + if (pdev->device != device) > > + return 1; > > + > > + while (t->device != 0) { > > + if (memcmp > > + ((char *) &pdev->subsystem_device, > > + (char *) &t->subsystem_device, sizeof(short)) == 0) > > + break; > > + t++; > > + index++; > > + } > > + > > + if (index >= max - 1) { > > + *desc = NULL; > > + *subsys_desc = NULL; > > + return 1; > > + } > > + > > + *desc = fnic_pcie_device_table[index].desc; > > + *subsys_desc = fnic_pcie_device_table[index].subsys_desc; > > + return 0; > > +} > Same here. Maybe move the PCI registration stuff to a different patch. Sure Hannes. I'll fix it in the next version of changes. > Cheers, > > Hannes > -- > Dr. Hannes Reinecke Kernel Storage Architect > hare@suse.de +49 911 74053 688 > SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg > HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich Regards, Karan
diff --git a/drivers/scsi/fnic/Makefile b/drivers/scsi/fnic/Makefile index 3bd6b1c8b643..af156c69da0c 100644 --- a/drivers/scsi/fnic/Makefile +++ b/drivers/scsi/fnic/Makefile @@ -16,4 +16,5 @@ fnic-y := \ vnic_intr.o \ vnic_rq.o \ vnic_wq_copy.o \ - vnic_wq.o + vnic_wq.o \ + fnic_pci_subsys_devid.o diff --git a/drivers/scsi/fnic/fdls_disc.c b/drivers/scsi/fnic/fdls_disc.c index a9a98ddc3a84..0b1d69ff19df 100644 --- a/drivers/scsi/fnic/fdls_disc.c +++ b/drivers/scsi/fnic/fdls_disc.c @@ -9,11 +9,23 @@ #include "fdls_fc.h" #include "fnic_fdls.h" #include <scsi/fc/fc_fcp.h> +#include <scsi/scsi_transport_fc.h> #include <linux/utsname.h> #define FC_FC4_TYPE_SCSI 0x08 +#define PORT_SPEED_BIT_8 8 +#define PORT_SPEED_BIT_9 9 +#define PORT_SPEED_BIT_14 14 +#define PORT_SPEED_BIT_15 15 static void fdls_send_rpn_id(struct fnic_iport_s *iport); +static void fdls_fdmi_register_hba(struct fnic_iport_s *iport); +static void fdls_fdmi_register_pa(struct fnic_iport_s *iport); +#define FDLS_FDMI_PLOGI_PENDING 0x1 +#define FDLS_FDMI_REG_HBA_PENDING 0x2 +#define FDLS_FDMI_RPA_PENDING 0x4 +#define FDLS_FDMI_ABORT_PENDING 0x8 +#define FDLS_FDMI_MAX_RETRY 3 /* Frame initialization */ /* @@ -84,6 +96,70 @@ struct fc_std_els_prli fnic_std_prli_req = { .spp_params = cpu_to_be32(0xA2)} }; +/* + * Variables: + * sid, port_id, port_name + */ +struct fc_std_fdmi_rhba fnic_std_fdmi_rhba = { + .fchdr = {.fh_r_ctl = FC_RCTL_DD_UNSOL_CTL, + .fh_d_id = {0xFF, 0XFF, 0XFA}, + .fh_type = FC_TYPE_CT, .fh_f_ctl = {FNIC_ELS_REQ_FCTL, 0, 0}, + .fh_rx_id = 0xFFFF}, + .fc_std_ct_hdr = {.ct_rev = FC_CT_REV, .ct_fs_type = FC_FST_MGMT, + .ct_fs_subtype = FC_FDMI_SUBTYPE, + .ct_cmd = cpu_to_be16(FC_FDMI_RHBA)}, + .num_ports = FNIC_FDMI_NUM_PORTS, + .num_hba_attributes = FNIC_FDMI_NUM_HBA_ATTRS, + .type_nn = FNIC_FDMI_TYPE_NODE_NAME, + .length_nn = FNIC_FDMI_NN_LEN, + .type_manu = FNIC_FDMI_TYPE_MANUFACTURER, + .length_manu = FNIC_FDMI_MANU_LEN, + .manufacturer = FNIC_FDMI_MANUFACTURER, + .type_serial = FNIC_FDMI_TYPE_SERIAL_NUMBER, + .length_serial = FNIC_FDMI_SERIAL_LEN, + .type_model = FNIC_FDMI_TYPE_MODEL, + .length_model = FNIC_FDMI_MODEL_LEN, + .type_model_des = FNIC_FDMI_TYPE_MODEL_DES, + .length_model_des = FNIC_FDMI_MODEL_DES_LEN, + .model_description = FNIC_FDMI_MODEL_DESCRIPTION, + .type_hw_ver = FNIC_FDMI_TYPE_HARDWARE_VERSION, + .length_hw_ver = FNIC_FDMI_HW_VER_LEN, + .type_dr_ver = FNIC_FDMI_TYPE_DRIVER_VERSION, + .length_dr_ver = FNIC_FDMI_DR_VER_LEN, + .type_rom_ver = FNIC_FDMI_TYPE_ROM_VERSION, + .length_rom_ver = FNIC_FDMI_ROM_VER_LEN, + .type_fw_ver = FNIC_FDMI_TYPE_FIRMWARE_VERSION, + .length_fw_ver = FNIC_FDMI_FW_VER_LEN, +}; + +/* + * Variables + *sid, port_id, port_name + */ +struct fc_std_fdmi_rpa fnic_std_fdmi_rpa = { + .fchdr = {.fh_r_ctl = FC_RCTL_DD_UNSOL_CTL, + .fh_d_id = {0xFF, 0xFF, 0xFA}, + .fh_type = FC_TYPE_CT, .fh_f_ctl = {FNIC_ELS_REQ_FCTL, 0, 0}, + .fh_rx_id = 0xFFFF}, + .fc_std_ct_hdr = {.ct_rev = FC_CT_REV, .ct_fs_type = FC_FST_MGMT, + .ct_fs_subtype = FC_FDMI_SUBTYPE, + .ct_cmd = cpu_to_be16(FC_FDMI_RPA)}, + .num_port_attributes = FNIC_FDMI_NUM_PORT_ATTRS, + .type_fc4 = FNIC_FDMI_TYPE_FC4_TYPES, + .length_fc4 = FNIC_FDMI_FC4_LEN, + .type_supp_speed = FNIC_FDMI_TYPE_SUPPORTED_SPEEDS, + .length_supp_speed = FNIC_FDMI_SUPP_SPEED_LEN, + .type_cur_speed = FNIC_FDMI_TYPE_CURRENT_SPEED, + .length_cur_speed = FNIC_FDMI_CUR_SPEED_LEN, + .type_max_frame_size = FNIC_FDMI_TYPE_MAX_FRAME_SIZE, + .length_max_frame_size = FNIC_FDMI_MFS_LEN, + .max_frame_size = FNIC_FDMI_MFS, + .type_os_name = FNIC_FDMI_TYPE_OS_NAME, + .length_os_name = FNIC_FDMI_OS_NAME_LEN, + .type_host_name = FNIC_FDMI_TYPE_HOST_NAME, + .length_host_name = FNIC_FDMI_HN_LEN, +}; + /* * Variables: * fh_s_id, port_id, port_name @@ -224,6 +300,7 @@ static void fdls_target_restart_nexus(struct fnic_tport_s *tport); static void fdls_start_tport_timer(struct fnic_iport_s *iport, struct fnic_tport_s *tport, int timeout); static void fdls_tport_timer_callback(struct timer_list *t); +static void fdls_send_fdmi_plogi(struct fnic_iport_s *iport); static void fdls_start_fabric_timer(struct fnic_iport_s *iport, int timeout); static void @@ -337,6 +414,15 @@ uint16_t fdls_alloc_fabric_oxid(struct fnic_iport_s *iport, * separately. */ switch (exp_rsp_type) { + case FNIC_FDMI_PLOGI_RSP: + oxid_pool->active_oxid_fdmi_plogi = oxid; + break; + case FNIC_FDMI_REG_HBA_RSP: + oxid_pool->active_oxid_fdmi_rhba = oxid; + break; + case FNIC_FDMI_RPA_RSP: + oxid_pool->active_oxid_fdmi_rpa = oxid; + break; default: oxid_pool->active_oxid_fabric_req = oxid; break; @@ -372,6 +458,21 @@ static inline void fdls_schedule_fabric_oxid_free(struct fnic_iport_s iport->fabric_oxid_pool.active_oxid_fabric_req); } +static inline void fdls_schedule_fdmi_oxid_free(struct fnic_iport_s *iport) +{ + if (iport->fabric.fdmi_pending & FDLS_FDMI_PLOGI_PENDING) + fdls_schedule_oxid_free(&iport->fdmi_oxid_pool.meta, + iport->fdmi_oxid_pool.active_oxid_fdmi_plogi); + + if (iport->fabric.fdmi_pending & FDLS_FDMI_REG_HBA_PENDING) + fdls_schedule_oxid_free(&iport->fdmi_oxid_pool.meta, + iport->fdmi_oxid_pool.active_oxid_fdmi_rhba); + + if (iport->fabric.fdmi_pending & FDLS_FDMI_RPA_PENDING) + fdls_schedule_oxid_free(&iport->fdmi_oxid_pool.meta, + iport->fdmi_oxid_pool.active_oxid_fdmi_rpa); +} + static inline void fdls_schedule_tgt_oxid_free(struct fnic_iport_s *iport, struct fnic_tgt_oxid_pool_s *oxid_pool, uint16_t oxid) @@ -406,6 +507,14 @@ static int fdls_is_oxid_in_fabric_range(uint16_t oxid) (oxid_unmasked <= FDLS_FABRIC_OXID_POOL_END)); } +static int fdls_is_oxid_in_fdmi_range(uint16_t oxid) +{ + uint16_t oxid_unmasked = FDLS_OXID_RSP_TYPE_UNMASKED(oxid); + + return ((oxid_unmasked >= FDLS_FDMI_OXID_POOL_BASE) && + (oxid_unmasked <= FDLS_FDMI_OXID_POOL_END)); +} + void fdls_init_tgt_oxid_pool(struct fnic_iport_s *iport) { memset(&iport->plogi_oxid_pool, 0, sizeof(iport->plogi_oxid_pool)); @@ -671,6 +780,42 @@ static void fdls_send_fabric_abts(struct fnic_iport_s *iport) iport->fabric.timer_pending = 1; } +static void fdls_send_fdmi_abts(struct fnic_iport_s *iport) +{ + uint8_t fcid[3]; + struct fc_frame_header fabric_abort = fc_std_fabric_abts; + struct fc_frame_header *fabric_abts = &fabric_abort; + struct fnic_fabric_oxid_pool_s *oxid_pool = &iport->fdmi_oxid_pool; + int fdmi_tov; + uint16_t oxid; + + hton24(fcid, 0XFFFFFA); + + if (iport->fabric.fdmi_pending & FDLS_FDMI_PLOGI_PENDING) { + oxid = htons(oxid_pool->active_oxid_fdmi_plogi); + FNIC_STD_SET_OX_ID(fabric_abts, oxid); + fnic_send_fcoe_frame(iport, fabric_abts, + sizeof(struct fc_frame_header)); + } else { + if (iport->fabric.fdmi_pending & FDLS_FDMI_REG_HBA_PENDING) { + oxid = htons(oxid_pool->active_oxid_fdmi_rhba); + FNIC_STD_SET_OX_ID(fabric_abts, oxid); + fnic_send_fcoe_frame(iport, fabric_abts, + sizeof(struct fc_frame_header)); + } + if (iport->fabric.fdmi_pending & FDLS_FDMI_RPA_PENDING) { + oxid = htons(oxid_pool->active_oxid_fdmi_rpa); + FNIC_STD_SET_OX_ID(fabric_abts, oxid); + fnic_send_fcoe_frame(iport, fabric_abts, + sizeof(struct fc_frame_header)); + } + } + + fdmi_tov = jiffies + msecs_to_jiffies(2 * iport->e_d_tov); + mod_timer(&iport->fabric.fdmi_timer, round_jiffies(fdmi_tov)); + iport->fabric.fdmi_pending |= FDLS_FDMI_ABORT_PENDING; +} + static void fdls_send_fabric_flogi(struct fnic_iport_s *iport) { struct fc_std_flogi flogi; @@ -738,6 +883,47 @@ static void fdls_send_fabric_plogi(struct fnic_iport_s *iport) fdls_start_fabric_timer(iport, 2 * iport->e_d_tov); } +static void fdls_send_fdmi_plogi(struct fnic_iport_s *iport) +{ + struct fc_std_flogi plogi; + struct fc_frame_header *fchdr = &plogi.fchdr; + uint8_t fcid[3]; + struct fnic *fnic = iport->fnic; + u64 fdmi_tov; + uint16_t oxid; + + memcpy(&plogi, &fnic_std_plogi_req, sizeof(plogi)); + + oxid = fdls_alloc_fabric_oxid(iport, &iport->fdmi_oxid_pool, + FNIC_FDMI_PLOGI_RSP); + if (oxid == 0xFFFF) { + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, + "Failed to allocate OXID to send fdmi plogi %p", + iport); + return; + } + + hton24(fcid, iport->fcid); + + FNIC_STD_SET_S_ID(fchdr, fcid); + hton24(fcid, 0XFFFFFA); + FNIC_STD_SET_D_ID(fchdr, fcid); + FNIC_STD_SET_OX_ID(fchdr, htons(oxid)); + FNIC_LOGI_SET_NPORT_NAME(&plogi.els, iport->wwpn); + FNIC_LOGI_SET_NODE_NAME(&plogi.els, iport->wwnn); + FNIC_LOGI_SET_RDF_SIZE(&plogi.els, iport->max_payload_size); + + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, + "fcid: 0x%x: FDLS send FDMI PLOGI with oxid:%x", + iport->fcid, oxid); + + fnic_send_fcoe_frame(iport, &plogi, sizeof(struct fc_std_flogi)); + + fdmi_tov = jiffies + msecs_to_jiffies(2 * iport->e_d_tov); + mod_timer(&iport->fabric.fdmi_timer, round_jiffies(fdmi_tov)); + iport->fabric.fdmi_pending = FDLS_FDMI_PLOGI_PENDING; +} + static void fdls_send_rpn_id(struct fnic_iport_s *iport) { struct fc_std_rpn_id rpn_id; @@ -1375,6 +1561,126 @@ struct fnic_tport_s *fnic_find_tport_by_wwpn(struct fnic_iport_s *iport, return NULL; } +static void fdls_fdmi_register_hba(struct fnic_iport_s *iport) +{ + struct fc_std_fdmi_rhba fdmi_rhba; + uint8_t fcid[3]; + uint16_t len; + int err; + struct fnic *fnic = iport->fnic; + struct vnic_devcmd_fw_info *fw_info = NULL; + uint16_t oxid; + + memcpy(&fdmi_rhba, &fnic_std_fdmi_rhba, + sizeof(struct fc_std_fdmi_rhba)); + + hton24(fcid, iport->fcid); + FNIC_STD_SET_S_ID((&fdmi_rhba.fchdr), fcid); + + oxid = fdls_alloc_fabric_oxid(iport, &iport->fdmi_oxid_pool, + FNIC_FDMI_REG_HBA_RSP); + if (oxid == 0xFFFF) { + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, + "Failed to allocate OXID to send fdmi reg hba %p", + iport); + return; + } + FNIC_STD_SET_OX_ID(&fdmi_rhba.fchdr, htons(oxid)); + + fdmi_rhba.hba_identifier = get_unaligned_be64(&iport->wwpn); + fdmi_rhba.port_name = get_unaligned_be64(&iport->wwpn); + fdmi_rhba.node_name = get_unaligned_be64(&iport->wwnn); + + err = vnic_dev_fw_info(fnic->vdev, &fw_info); + if (!err) { + snprintf(fdmi_rhba.serial_num, sizeof(fdmi_rhba.serial_num) - 1, + "%s", fw_info->hw_serial_number); + snprintf(fdmi_rhba.hardware_ver, + sizeof(fdmi_rhba.hardware_ver) - 1, "%s", + fw_info->hw_version); + strscpy(fdmi_rhba.firmware_ver, fw_info->fw_version, + sizeof(fdmi_rhba.firmware_ver) - 1); + + len = ARRAY_SIZE(fdmi_rhba.model); + if (fnic->subsys_desc_len >= len) + fnic->subsys_desc_len = len - 1; + memcpy(&fdmi_rhba.model, fnic->subsys_desc, + fnic->subsys_desc_len); + fdmi_rhba.model[fnic->subsys_desc_len] = 0x00; + } + + snprintf(fdmi_rhba.driver_ver, sizeof(fdmi_rhba.driver_ver) - 1, "%s", + DRV_VERSION); + snprintf(fdmi_rhba.rom_ver, sizeof(fdmi_rhba.rom_ver) - 1, "%s", "N/A"); + + fnic_send_fcoe_frame(iport, &fdmi_rhba, + sizeof(struct fc_std_fdmi_rhba)); + iport->fabric.fdmi_pending |= FDLS_FDMI_REG_HBA_PENDING; +} + +static void fdls_fdmi_register_pa(struct fnic_iport_s *iport) +{ + struct fc_std_fdmi_rpa fdmi_rpa; + + uint8_t fcid[3]; + struct fnic *fnic = iport->fnic; + u32 port_speed_bm; + u32 port_speed = vnic_dev_port_speed(fnic->vdev); + uint16_t oxid; + + memcpy(&fdmi_rpa, &fnic_std_fdmi_rpa, sizeof(struct fc_std_fdmi_rpa)); + hton24(fcid, iport->fcid); + FNIC_STD_SET_S_ID((&fdmi_rpa.fchdr), fcid); + + oxid = fdls_alloc_fabric_oxid(iport, &iport->fdmi_oxid_pool, + FNIC_FDMI_RPA_RSP); + if (oxid == 0xFFFF) { + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, + "Failed to allocate OXID to send fdmi rpa %p", + iport); + return; + } + FNIC_STD_SET_OX_ID(&fdmi_rpa.fchdr, htons(oxid)); + + fdmi_rpa.port_name = get_unaligned_be64(&iport->wwpn); + + /* MDS does not support GIGE speed. + * Bit shift standard definitions from scsi_transport_fc.h to + * match FC spec. + */ + switch (port_speed) { + case DCEM_PORTSPEED_10G: + case DCEM_PORTSPEED_20G: + /* There is no bit for 20G */ + port_speed_bm = FC_PORTSPEED_10GBIT << PORT_SPEED_BIT_14; + break; + case DCEM_PORTSPEED_25G: + port_speed_bm = FC_PORTSPEED_25GBIT << PORT_SPEED_BIT_8; + break; + case DCEM_PORTSPEED_40G: + case DCEM_PORTSPEED_4x10G: + port_speed_bm = FC_PORTSPEED_40GBIT << PORT_SPEED_BIT_9; + break; + case DCEM_PORTSPEED_100G: + port_speed_bm = FC_PORTSPEED_100GBIT << PORT_SPEED_BIT_8; + break; + default: + port_speed_bm = FC_PORTSPEED_1GBIT << PORT_SPEED_BIT_15; + break; + } + fdmi_rpa.supported_speed = htonl(port_speed_bm); + fdmi_rpa.current_speed = htonl(port_speed_bm); + fdmi_rpa.fc4_type[2] = 1; + snprintf(fdmi_rpa.os_name, sizeof(fdmi_rpa.os_name) - 1, "host%d", + fnic->lport->host->host_no); + sprintf(fc_host_system_hostname(fnic->lport->host), "%s", utsname()->nodename); + snprintf(fdmi_rpa.host_name, sizeof(fdmi_rpa.host_name) - 1, "%s", + fc_host_system_hostname(fnic->lport->host)); + + fnic_send_fcoe_frame(iport, &fdmi_rpa, sizeof(struct fc_std_fdmi_rpa)); + iport->fabric.fdmi_pending |= FDLS_FDMI_RPA_PENDING; +} + void fdls_fabric_timer_callback(struct timer_list *t) { struct fnic_fdls_fabric_s *fabric = from_timer(fabric, t, retry_timer); @@ -1548,6 +1854,43 @@ void fdls_fabric_timer_callback(struct timer_list *t) spin_unlock_irqrestore(&fnic->fnic_lock, flags); } +void fdls_fdmi_timer_callback(struct timer_list *t) +{ + struct fnic_fdls_fabric_s *fabric = from_timer(fabric, t, fdmi_timer); + struct fnic_iport_s *iport = + container_of(fabric, struct fnic_iport_s, fabric); + struct fnic *fnic = iport->fnic; + unsigned long flags; + + spin_lock_irqsave(&fnic->fnic_lock, flags); + + if (!iport->fabric.fdmi_pending) { + /* timer expired after fdmi responses received. */ + spin_unlock_irqrestore(&fnic->fnic_lock, flags); + return; + } + + /* if not abort pending, send an abort */ + if (!(iport->fabric.fdmi_pending & FDLS_FDMI_ABORT_PENDING)) { + fdls_send_fdmi_abts(iport); + spin_unlock_irqrestore(&fnic->fnic_lock, flags); + return; + } + + /* Abort timed out */ + fdls_schedule_fdmi_oxid_free(iport); + + iport->fabric.fdmi_pending = 0; + /* If max retries not exhaused, start over from fdmi plogi */ + if (iport->fabric.fdmi_retry < FDLS_FDMI_MAX_RETRY) { + iport->fabric.fdmi_retry++; + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, + "retry fdmi timer %d", iport->fabric.fdmi_retry); + fdls_send_fdmi_plogi(iport); + } + spin_unlock_irqrestore(&fnic->fnic_lock, flags); +} + static void fdls_send_delete_tport_msg(struct fnic_tport_s *tport) { struct fnic_iport_s *iport = (struct fnic_iport_s *) tport->iport; @@ -1697,6 +2040,15 @@ static void fnic_fdls_start_plogi(struct fnic_iport_s *iport) fdls_send_fabric_plogi(iport); fdls_set_state((&iport->fabric), FDLS_STATE_FABRIC_PLOGI); iport->fabric.flags &= ~FNIC_FDLS_FABRIC_ABORT_ISSUED; + + if ((fnic_fdmi_support == 1) && (!(iport->flags & FNIC_FDMI_ACTIVE))) { + /* we can do FDMI at the same time */ + iport->fabric.fdmi_retry = 0; + timer_setup(&iport->fabric.fdmi_timer, fdls_fdmi_timer_callback, + 0); + fdls_send_fdmi_plogi(iport); + iport->flags |= FNIC_FDMI_ACTIVE; + } } static void @@ -2784,6 +3136,109 @@ fdls_process_fabric_plogi_rsp(struct fnic_iport_s *iport, } } +static void fdls_process_fdmi_plogi_rsp(struct fnic_iport_s *iport, + struct fc_frame_header *fchdr) +{ + struct fc_std_flogi *plogi_rsp = (struct fc_std_flogi *)fchdr; + struct fc_std_els_rsp *els_rjt = (struct fc_std_els_rsp *)fchdr; + struct fnic *fnic = iport->fnic; + u64 fdmi_tov; + + iport->fabric.fdmi_pending &= ~FDLS_FDMI_PLOGI_PENDING; + fdls_free_fabric_oxid(iport, &iport->fabric_oxid_pool, + ntohs(FNIC_STD_GET_OX_ID(fchdr))); + + if (ntoh24(fchdr->fh_s_id) == 0XFFFFFA) { + del_timer_sync(&iport->fabric.fdmi_timer); + iport->fabric.fdmi_pending = 0; + switch (plogi_rsp->els.fl_cmd) { + case ELS_LS_ACC: + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, + "FDLS process fdmi PLOGI response status: ELS_LS_ACC\n"); + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, + "Sending fdmi registration for port 0x%x\n", + iport->fcid); + + fdls_fdmi_register_hba(iport); + fdls_fdmi_register_pa(iport); + fdmi_tov = jiffies + msecs_to_jiffies(5000); + mod_timer(&iport->fabric.fdmi_timer, + round_jiffies(fdmi_tov)); + break; + case ELS_LS_RJT: + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, + "Fabric FDMI PLOGI returned ELS_LS_RJT reason: 0x%x", + els_rjt->u.rej.er_reason); + + if (((els_rjt->u.rej.er_reason == ELS_RJT_BUSY) + || (els_rjt->u.rej.er_reason == ELS_RJT_UNAB)) + && (iport->fabric.fdmi_retry < 7)) { + iport->fabric.fdmi_retry++; + fdls_send_fdmi_plogi(iport); + } + break; + default: + break; + } + } +} + +static void fdls_process_fdmi_reg_ack(struct fnic_iport_s *iport, + struct fc_frame_header *fchdr, + int rsp_type) +{ + struct fnic *fnic = iport->fnic; + + if (!iport->fabric.fdmi_pending) { + FNIC_FCS_DBG(KERN_ERR, fnic->lport->host, fnic->fnic_num, + "Received FDMI ack while not waiting:%x\n", + ntohs(FNIC_STD_GET_OX_ID(fchdr))); + return; + } + + if (rsp_type == FNIC_FDMI_REG_HBA_RSP) + iport->fabric.fdmi_pending &= ~FDLS_FDMI_REG_HBA_PENDING; + else + iport->fabric.fdmi_pending &= ~FDLS_FDMI_RPA_PENDING; + + fdls_free_fabric_oxid(iport, &iport->fdmi_oxid_pool, + ntohs(FNIC_STD_GET_OX_ID(fchdr))); + + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, + "iport fcid: 0x%x: Received FDMI registration ack\n", + iport->fcid); + + if (!iport->fabric.fdmi_pending) { + del_timer_sync(&iport->fabric.fdmi_timer); + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, + "iport fcid: 0x%x: Canceling FDMI timer\n", + iport->fcid); + } +} + +static void fdls_process_fdmi_abts_rsp(struct fnic_iport_s *iport, + struct fc_frame_header *fchdr) +{ + uint32_t s_id; + struct fnic *fnic = iport->fnic; + + s_id = ntoh24(FNIC_STD_GET_S_ID(fchdr)); + + if (!(s_id != 0xFFFFFA)) { + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, + "Received abts rsp with invalid SID: 0x%x. Dropping frame", + s_id); + return; + } + + del_timer_sync(&iport->fabric.fdmi_timer); + iport->fabric.fdmi_pending &= ~FDLS_FDMI_ABORT_PENDING; + + fdls_free_fabric_oxid(iport, &iport->fdmi_oxid_pool, + ntohs(FNIC_STD_GET_OX_ID(fchdr))); + fdls_send_fdmi_plogi(iport); +} + static void fdls_process_fabric_abts_rsp(struct fnic_iport_s *iport, struct fc_frame_header *fchdr) @@ -3780,6 +4235,9 @@ fnic_fdls_validate_and_get_frame_type(struct fnic_iport_s *iport, break; case FNIC_FABRIC_LOGO_RSP: + case FNIC_FDMI_PLOGI_RSP: + case FNIC_FDMI_REG_HBA_RSP: + case FNIC_FDMI_RPA_RSP: break; default: /* Drop the Rx frame and log/stats it */ @@ -3822,6 +4280,9 @@ void fnic_fdls_recv_frame(struct fnic_iport_s *iport, void *rx_frame, case FNIC_FABRIC_PLOGI_RSP: fdls_process_fabric_plogi_rsp(iport, fchdr); break; + case FNIC_FDMI_PLOGI_RSP: + fdls_process_fdmi_plogi_rsp(iport, fchdr); + break; case FNIC_FABRIC_RPN_RSP: fdls_process_rpn_id_rsp(iport, fchdr); break; @@ -3861,6 +4322,9 @@ void fnic_fdls_recv_frame(struct fnic_iport_s *iport, void *rx_frame, if (fdls_is_oxid_in_fabric_range(oxid) && (iport->fabric.flags & FNIC_FDLS_FABRIC_ABORT_ISSUED)) { fdls_process_fabric_abts_rsp(iport, fchdr); + } else if (fdls_is_oxid_in_fdmi_range(oxid) && + iport->fabric.fdmi_pending) { + fdls_process_fdmi_abts_rsp(iport, fchdr); } else { fdls_process_tgt_abts_rsp(iport, fchdr); } @@ -3890,6 +4354,10 @@ void fnic_fdls_recv_frame(struct fnic_iport_s *iport, void *rx_frame, case FNIC_ELS_RLS: fdls_process_rls_req(iport, fchdr); break; + case FNIC_FDMI_REG_HBA_RSP: + case FNIC_FDMI_RPA_RSP: + fdls_process_fdmi_reg_ack(iport, fchdr, frame_type); + break; default: FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, "s_id: 0x%x d_did: 0x%x", s_id, d_id); diff --git a/drivers/scsi/fnic/fnic.h b/drivers/scsi/fnic/fnic.h index 92cd17efa40f..5d8315b24085 100644 --- a/drivers/scsi/fnic/fnic.h +++ b/drivers/scsi/fnic/fnic.h @@ -82,6 +82,72 @@ /* Retry supported by rport (returned by PRLI service parameters) */ #define FNIC_FC_RP_FLAGS_RETRY 0x1 +/* Cisco vendor id */ +#define PCI_VENDOR_ID_CISCO 0x1137 +#define PCI_DEVICE_ID_CISCO_VIC_FC 0x0045 /* fc vnic */ + +/* sereno pcie switch */ +#define PCI_DEVICE_ID_CISCO_SERENO 0x004e +#define PCI_DEVICE_ID_CISCO_CRUZ 0x007a /* Cruz */ +#define PCI_DEVICE_ID_CISCO_BODEGA 0x0131 /* Bodega */ +#define PCI_DEVICE_ID_CISCO_BEVERLY 0x025f /* Beverly */ + +/* Sereno */ +#define PCI_SUBDEVICE_ID_CISCO_VASONA 0x004f /* vasona mezz */ +#define PCI_SUBDEVICE_ID_CISCO_COTATI 0x0084 /* cotati mlom */ +#define PCI_SUBDEVICE_ID_CISCO_LEXINGTON 0x0085 /* lexington pcie */ +#define PCI_SUBDEVICE_ID_CISCO_ICEHOUSE 0x00cd /* Icehouse */ +#define PCI_SUBDEVICE_ID_CISCO_KIRKWOODLAKE 0x00ce /* KirkwoodLake pcie */ +#define PCI_SUBDEVICE_ID_CISCO_SUSANVILLE 0x012e /* Susanville MLOM */ +#define PCI_SUBDEVICE_ID_CISCO_TORRANCE 0x0139 /* Torrance MLOM */ + +/* Cruz */ +#define PCI_SUBDEVICE_ID_CISCO_CALISTOGA 0x012c /* Calistoga MLOM */ +#define PCI_SUBDEVICE_ID_CISCO_MOUNTAINVIEW 0x0137 /* Cruz Mezz */ +/* Cruz MountTian SIOC */ +#define PCI_SUBDEVICE_ID_CISCO_MOUNTTIAN 0x014b +#define PCI_SUBDEVICE_ID_CISCO_CLEARLAKE 0x014d /* ClearLake pcie */ +/* Cruz MountTian2 SIOC */ +#define PCI_SUBDEVICE_ID_CISCO_MOUNTTIAN2 0x0157 +#define PCI_SUBDEVICE_ID_CISCO_CLAREMONT 0x015d /* Claremont MLOM */ + +/* Bodega */ +/* VIC 1457 PCIe mLOM */ +#define PCI_SUBDEVICE_ID_CISCO_BRADBURY 0x0218 +#define PCI_SUBDEVICE_ID_CISCO_BRENTWOOD 0x0217 /* VIC 1455 PCIe */ +/* VIC 1487 PCIe mLOM */ +#define PCI_SUBDEVICE_ID_CISCO_BURLINGAME 0x021a +#define PCI_SUBDEVICE_ID_CISCO_BAYSIDE 0x0219 /* VIC 1485 PCIe */ +/* VIC 1440 Mezz mLOM */ +#define PCI_SUBDEVICE_ID_CISCO_BAKERSFIELD 0x0215 +#define PCI_SUBDEVICE_ID_CISCO_BOONVILLE 0x0216 /* VIC 1480 Mezz */ +#define PCI_SUBDEVICE_ID_CISCO_BENICIA 0x024a /* VIC 1495 */ +#define PCI_SUBDEVICE_ID_CISCO_BEAUMONT 0x024b /* VIC 1497 */ +#define PCI_SUBDEVICE_ID_CISCO_BRISBANE 0x02af /* VIC 1467 */ +#define PCI_SUBDEVICE_ID_CISCO_BENTON 0x02b0 /* VIC 1477 */ +#define PCI_SUBDEVICE_ID_CISCO_TWIN_RIVER 0x02cf /* VIC 14425 */ +#define PCI_SUBDEVICE_ID_CISCO_TWIN_PEAK 0x02d0 /* VIC 14825 */ + +/* Beverly */ +#define PCI_SUBDEVICE_ID_CISCO_BERN 0x02de /* VIC 15420 */ +#define PCI_SUBDEVICE_ID_CISCO_STOCKHOLM 0x02dd /* VIC 15428 */ +#define PCI_SUBDEVICE_ID_CISCO_KRAKOW 0x02dc /* VIC 15411 */ +#define PCI_SUBDEVICE_ID_CISCO_LUCERNE 0x02db /* VIC 15231 */ +#define PCI_SUBDEVICE_ID_CISCO_TURKU 0x02e8 /* VIC 15238 */ +#define PCI_SUBDEVICE_ID_CISCO_TURKU_PLUS 0x02f3 /* VIC 15237 */ +#define PCI_SUBDEVICE_ID_CISCO_ZURICH 0x02df /* VIC 15230 */ +#define PCI_SUBDEVICE_ID_CISCO_RIGA 0x02e0 /* VIC 15427 */ +#define PCI_SUBDEVICE_ID_CISCO_GENEVA 0x02e1 /* VIC 15422 */ +#define PCI_SUBDEVICE_ID_CISCO_HELSINKI 0x02e4 /* VIC 15235 */ +#define PCI_SUBDEVICE_ID_CISCO_GOTHENBURG 0x02f2 /* VIC 15425 */ + +struct fnic_pcie_device { + u32 device; + u8 *desc; + u32 subsystem_device; + u8 *subsys_desc; +}; + /* * fnic private data per SCSI command. * These fields are locked by the hashed io_req_lock. @@ -134,6 +200,7 @@ static inline u64 fnic_flags_and_state(struct scsi_cmnd *cmd) #define fnic_clear_state_flags(fnicp, st_flags) \ __fnic_set_state_flags(fnicp, st_flags, 1) +extern unsigned int fnic_fdmi_support; extern unsigned int fnic_log_level; extern unsigned int io_completions; extern struct workqueue_struct *fnic_event_queue; @@ -336,6 +403,9 @@ struct fnic { struct work_struct tport_work; struct list_head tport_event_list; + char subsys_desc[14]; + int subsys_desc_len; + /*** FIP related data members -- start ***/ void (*set_vlan)(struct fnic *, u16 vlan); struct work_struct fip_frame_work; @@ -433,5 +503,7 @@ fnic_chk_state_flags_locked(struct fnic *fnic, unsigned long st_flags) void __fnic_set_state_flags(struct fnic *, unsigned long, unsigned long); void fnic_dump_fchost_stats(struct Scsi_Host *, struct fc_host_statistics *); void fnic_free_txq(struct list_head *head); +int fnic_get_desc_by_devid(struct pci_dev *pdev, char **desc, + char **subsys_desc); #endif /* _FNIC_H_ */ diff --git a/drivers/scsi/fnic/fnic_main.c b/drivers/scsi/fnic/fnic_main.c index 16c9f87c932b..c8d2fcf5d948 100644 --- a/drivers/scsi/fnic/fnic_main.c +++ b/drivers/scsi/fnic/fnic_main.c @@ -62,6 +62,9 @@ unsigned int fnic_log_level; module_param(fnic_log_level, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(fnic_log_level, "bit mask of fnic logging levels"); +unsigned int fnic_fdmi_support = 1; +module_param(fnic_fdmi_support, int, 0644); +MODULE_PARM_DESC(fnic_fdmi_support, "FDMI support"); unsigned int io_completions = FNIC_DFLT_IO_COMPLETIONS; module_param(io_completions, int, S_IRUGO|S_IWUSR); @@ -607,6 +610,8 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) int i; unsigned long flags; int hwq; + char *desc, *subsys_desc; + int len; /* * Allocate SCSI Host and set up association between host, @@ -640,6 +645,23 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) fnic->fnic_num = fnic_id; fnic_stats_debugfs_init(fnic); + /* Find model name from PCIe subsys ID */ + if (fnic_get_desc_by_devid(pdev, &desc, &subsys_desc) == 0) { + dev_info(&fnic->pdev->dev, "Model: %s\n", subsys_desc); + + /* Update FDMI model */ + fnic->subsys_desc_len = strlen(subsys_desc); + len = ARRAY_SIZE(fnic->subsys_desc); + if (fnic->subsys_desc_len > len) + fnic->subsys_desc_len = len; + memcpy(fnic->subsys_desc, subsys_desc, fnic->subsys_desc_len); + dev_info(&fnic->pdev->dev, "FDMI Model: %s\n", fnic->subsys_desc); + } else { + fnic->subsys_desc_len = 0; + dev_info(&fnic->pdev->dev, "Model: %s subsys_id: 0x%04x\n", "Unknown", + pdev->subsystem_device); + } + err = pci_enable_device(pdev); if (err) { dev_err(&fnic->pdev->dev, "Cannot enable PCI device, aborting.\n"); @@ -1014,6 +1036,9 @@ static void fnic_remove(struct pci_dev *pdev) fnic_fcoe_evlist_free(fnic); } + if ((fnic_fdmi_support == 1) && (fnic->iport.fabric.fdmi_pending > 0)) + del_timer_sync(&fnic->iport.fabric.fdmi_timer); + /* * Log off the fabric. This stops all remote ports, dns port, * logs off the fabric. This flushes all rport, disc, lport work diff --git a/drivers/scsi/fnic/fnic_pci_subsys_devid.c b/drivers/scsi/fnic/fnic_pci_subsys_devid.c new file mode 100644 index 000000000000..36a2c1268422 --- /dev/null +++ b/drivers/scsi/fnic/fnic_pci_subsys_devid.c @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright 2008 Cisco Systems, Inc. All rights reserved. + * Copyright 2007 Nuova Systems, Inc. All rights reserved. + */ + +#include <linux/module.h> +#include <linux/mempool.h> +#include <linux/string.h> +#include <linux/slab.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/spinlock.h> +#include <linux/workqueue.h> +#include <linux/kthread.h> +#include <linux/if_ether.h> +#include "fnic.h" + +static struct fnic_pcie_device fnic_pcie_device_table[] = { + {PCI_DEVICE_ID_CISCO_SERENO, "Sereno", PCI_SUBDEVICE_ID_CISCO_VASONA, + "VIC 1280"}, + {PCI_DEVICE_ID_CISCO_SERENO, "Sereno", PCI_SUBDEVICE_ID_CISCO_COTATI, + "VIC 1240"}, + {PCI_DEVICE_ID_CISCO_SERENO, "Sereno", + PCI_SUBDEVICE_ID_CISCO_LEXINGTON, "VIC 1225"}, + {PCI_DEVICE_ID_CISCO_SERENO, "Sereno", PCI_SUBDEVICE_ID_CISCO_ICEHOUSE, + "VIC 1285"}, + {PCI_DEVICE_ID_CISCO_SERENO, "Sereno", + PCI_SUBDEVICE_ID_CISCO_KIRKWOODLAKE, "VIC 1225T"}, + {PCI_DEVICE_ID_CISCO_SERENO, "Sereno", + PCI_SUBDEVICE_ID_CISCO_SUSANVILLE, "VIC 1227"}, + {PCI_DEVICE_ID_CISCO_SERENO, "Sereno", PCI_SUBDEVICE_ID_CISCO_TORRANCE, + "VIC 1227T"}, + + {PCI_DEVICE_ID_CISCO_CRUZ, "Cruz", PCI_SUBDEVICE_ID_CISCO_CALISTOGA, + "VIC 1340"}, + {PCI_DEVICE_ID_CISCO_CRUZ, "Cruz", PCI_SUBDEVICE_ID_CISCO_MOUNTAINVIEW, + "VIC 1380"}, + {PCI_DEVICE_ID_CISCO_CRUZ, "Cruz", PCI_SUBDEVICE_ID_CISCO_MOUNTTIAN, + "C3260-SIOC"}, + {PCI_DEVICE_ID_CISCO_CRUZ, "Cruz", PCI_SUBDEVICE_ID_CISCO_CLEARLAKE, + "VIC 1385"}, + {PCI_DEVICE_ID_CISCO_CRUZ, "Cruz", PCI_SUBDEVICE_ID_CISCO_MOUNTTIAN2, + "C3260-SIOC"}, + {PCI_DEVICE_ID_CISCO_CRUZ, "Cruz", PCI_SUBDEVICE_ID_CISCO_CLAREMONT, + "VIC 1387"}, + + {PCI_DEVICE_ID_CISCO_BODEGA, "Bodega", PCI_SUBDEVICE_ID_CISCO_BRADBURY, + "VIC 1457"}, + {PCI_DEVICE_ID_CISCO_BODEGA, "Bodega", + PCI_SUBDEVICE_ID_CISCO_BRENTWOOD, "VIC 1455"}, + {PCI_DEVICE_ID_CISCO_BODEGA, "Bodega", + PCI_SUBDEVICE_ID_CISCO_BURLINGAME, "VIC 1487"}, + {PCI_DEVICE_ID_CISCO_BODEGA, "Bodega", PCI_SUBDEVICE_ID_CISCO_BAYSIDE, + "VIC 1485"}, + {PCI_DEVICE_ID_CISCO_BODEGA, "Bodega", + PCI_SUBDEVICE_ID_CISCO_BAKERSFIELD, "VIC 1440"}, + {PCI_DEVICE_ID_CISCO_BODEGA, "Bodega", + PCI_SUBDEVICE_ID_CISCO_BOONVILLE, "VIC 1480"}, + {PCI_DEVICE_ID_CISCO_BODEGA, "Bodega", PCI_SUBDEVICE_ID_CISCO_BENICIA, + "VIC 1495"}, + {PCI_DEVICE_ID_CISCO_BODEGA, "Bodega", PCI_SUBDEVICE_ID_CISCO_BEAUMONT, + "VIC 1497"}, + {PCI_DEVICE_ID_CISCO_BODEGA, "Bodega", PCI_SUBDEVICE_ID_CISCO_BRISBANE, + "VIC 1467"}, + {PCI_DEVICE_ID_CISCO_BODEGA, "Bodega", PCI_SUBDEVICE_ID_CISCO_BENTON, + "VIC 1477"}, + {PCI_DEVICE_ID_CISCO_BODEGA, "Bodega", + PCI_SUBDEVICE_ID_CISCO_TWIN_RIVER, "VIC 14425"}, + {PCI_DEVICE_ID_CISCO_BODEGA, "Bodega", + PCI_SUBDEVICE_ID_CISCO_TWIN_PEAK, "VIC 14825"}, + + {PCI_DEVICE_ID_CISCO_BEVERLY, "Beverly", PCI_SUBDEVICE_ID_CISCO_BERN, + "VIC 15420"}, + {PCI_DEVICE_ID_CISCO_BEVERLY, "Beverly", + PCI_SUBDEVICE_ID_CISCO_STOCKHOLM, "VIC 15428"}, + {PCI_DEVICE_ID_CISCO_BEVERLY, "Beverly", PCI_SUBDEVICE_ID_CISCO_KRAKOW, + "VIC 15411"}, + {PCI_DEVICE_ID_CISCO_BEVERLY, "Beverly", + PCI_SUBDEVICE_ID_CISCO_LUCERNE, "VIC 15231"}, + {PCI_DEVICE_ID_CISCO_BEVERLY, "Beverly", PCI_SUBDEVICE_ID_CISCO_TURKU, + "VIC 15238"}, + {PCI_DEVICE_ID_CISCO_BEVERLY, "Beverly", PCI_SUBDEVICE_ID_CISCO_GENEVA, + "VIC 15422"}, + {PCI_DEVICE_ID_CISCO_BEVERLY, "Beverly", + PCI_SUBDEVICE_ID_CISCO_HELSINKI, "VIC 15235"}, + {PCI_DEVICE_ID_CISCO_BEVERLY, "Beverly", + PCI_SUBDEVICE_ID_CISCO_GOTHENBURG, "VIC 15425"}, + {PCI_DEVICE_ID_CISCO_BEVERLY, "Beverly", + PCI_SUBDEVICE_ID_CISCO_TURKU_PLUS, "VIC 15237"}, + {PCI_DEVICE_ID_CISCO_BEVERLY, "Beverly", PCI_SUBDEVICE_ID_CISCO_ZURICH, + "VIC 15230"}, + {PCI_DEVICE_ID_CISCO_BEVERLY, "Beverly", PCI_SUBDEVICE_ID_CISCO_RIGA, + "VIC 15427"}, + + {0,} +}; + +int fnic_get_desc_by_devid(struct pci_dev *pdev, char **desc, + char **subsys_desc) +{ + unsigned short device = PCI_DEVICE_ID_CISCO_VIC_FC; + int max = ARRAY_SIZE(fnic_pcie_device_table); + struct fnic_pcie_device *t = fnic_pcie_device_table; + int index = 0; + + if (pdev->device != device) + return 1; + + while (t->device != 0) { + if (memcmp + ((char *) &pdev->subsystem_device, + (char *) &t->subsystem_device, sizeof(short)) == 0) + break; + t++; + index++; + } + + if (index >= max - 1) { + *desc = NULL; + *subsys_desc = NULL; + return 1; + } + + *desc = fnic_pcie_device_table[index].desc; + *subsys_desc = fnic_pcie_device_table[index].subsys_desc; + return 0; +}