diff options
Diffstat (limited to 'drivers/scsi/cxlflash/main.c')
-rw-r--r-- | drivers/scsi/cxlflash/main.c | 77 |
1 files changed, 58 insertions, 19 deletions
diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index e198605c3ded..64ad76b6b672 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -1028,25 +1028,29 @@ static void afu_link_reset(struct afu *afu, int port, __be64 __iomem *fc_regs) /* * Asynchronous interrupt information table + * + * NOTE: The checkpatch script considers the BUILD_SISL_ASTATUS_FC_PORT macro + * as complex and complains because it is not wrapped with parentheses/braces. */ +#define ASTATUS_FC(_a, _b, _c, _d) \ + { SISL_ASTATUS_FC##_a##_##_b, _c, _a, (_d) } + +#define BUILD_SISL_ASTATUS_FC_PORT(_a) \ + ASTATUS_FC(_a, OTHER, "other error", CLR_FC_ERROR | LINK_RESET), \ + ASTATUS_FC(_a, LOGO, "target initiated LOGO", 0), \ + ASTATUS_FC(_a, CRC_T, "CRC threshold exceeded", LINK_RESET), \ + ASTATUS_FC(_a, LOGI_R, "login timed out, retrying", LINK_RESET), \ + ASTATUS_FC(_a, LOGI_F, "login failed", CLR_FC_ERROR), \ + ASTATUS_FC(_a, LOGI_S, "login succeeded", SCAN_HOST), \ + ASTATUS_FC(_a, LINK_DN, "link down", 0), \ + ASTATUS_FC(_a, LINK_UP, "link up", 0) + static const struct asyc_intr_info ainfo[] = { - {SISL_ASTATUS_FC0_OTHER, "other error", 0, CLR_FC_ERROR | LINK_RESET}, - {SISL_ASTATUS_FC0_LOGO, "target initiated LOGO", 0, 0}, - {SISL_ASTATUS_FC0_CRC_T, "CRC threshold exceeded", 0, LINK_RESET}, - {SISL_ASTATUS_FC0_LOGI_R, "login timed out, retrying", 0, LINK_RESET}, - {SISL_ASTATUS_FC0_LOGI_F, "login failed", 0, CLR_FC_ERROR}, - {SISL_ASTATUS_FC0_LOGI_S, "login succeeded", 0, SCAN_HOST}, - {SISL_ASTATUS_FC0_LINK_DN, "link down", 0, 0}, - {SISL_ASTATUS_FC0_LINK_UP, "link up", 0, 0}, - {SISL_ASTATUS_FC1_OTHER, "other error", 1, CLR_FC_ERROR | LINK_RESET}, - {SISL_ASTATUS_FC1_LOGO, "target initiated LOGO", 1, 0}, - {SISL_ASTATUS_FC1_CRC_T, "CRC threshold exceeded", 1, LINK_RESET}, - {SISL_ASTATUS_FC1_LOGI_R, "login timed out, retrying", 1, LINK_RESET}, - {SISL_ASTATUS_FC1_LOGI_F, "login failed", 1, CLR_FC_ERROR}, - {SISL_ASTATUS_FC1_LOGI_S, "login succeeded", 1, SCAN_HOST}, - {SISL_ASTATUS_FC1_LINK_DN, "link down", 1, 0}, - {SISL_ASTATUS_FC1_LINK_UP, "link up", 1, 0}, - {0x0, "", 0, 0} /* terminator */ + BUILD_SISL_ASTATUS_FC_PORT(2), + BUILD_SISL_ASTATUS_FC_PORT(3), + BUILD_SISL_ASTATUS_FC_PORT(0), + BUILD_SISL_ASTATUS_FC_PORT(1), + { 0x0, "", 0, 0 } }; /** @@ -1059,6 +1063,8 @@ static const struct asyc_intr_info *find_ainfo(u64 status) { const struct asyc_intr_info *info; + BUILD_BUG_ON(ainfo[ARRAY_SIZE(ainfo) - 1].status != 0); + for (info = &ainfo[0]; info->status; info++) if (info->status == status) return info; @@ -1747,6 +1753,39 @@ out: } /** + * get_num_afu_ports() - determines and configures the number of AFU ports + * @cfg: Internal structure associated with the host. + * + * This routine determines the number of AFU ports by converting the global + * port selection mask. The converted value is only valid following an AFU + * reset (explicit or power-on). This routine must be invoked shortly after + * mapping as other routines are dependent on the number of ports during the + * initialization sequence. + * + * To support legacy AFUs that might not have reflected an initial global + * port mask (value read is 0), default to the number of ports originally + * supported by the cxlflash driver (2) before hardware with other port + * offerings was introduced. + */ +static void get_num_afu_ports(struct cxlflash_cfg *cfg) +{ + struct afu *afu = cfg->afu; + struct device *dev = &cfg->dev->dev; + u64 port_mask; + int num_fc_ports = LEGACY_FC_PORTS; + + port_mask = readq_be(&afu->afu_map->global.regs.afu_port_sel); + if (port_mask != 0ULL) + num_fc_ports = min(ilog2(port_mask) + 1, MAX_FC_PORTS); + + dev_dbg(dev, "%s: port_mask=%016llx num_fc_ports=%d\n", + __func__, port_mask, num_fc_ports); + + cfg->num_fc_ports = num_fc_ports; + cfg->host->max_channel = PORTNUM2CHAN(num_fc_ports); +} + +/** * init_afu() - setup as master context and start AFU * @cfg: Internal structure associated with the host. * @@ -1803,6 +1842,8 @@ static int init_afu(struct cxlflash_cfg *cfg) dev_dbg(dev, "%s: afu_ver=%s interface_ver=%016llx\n", __func__, afu->version, afu->interface_version); + get_num_afu_ports(cfg); + rc = start_afu(cfg); if (rc) { dev_err(dev, "%s: start_afu failed, rc=%d\n", __func__, rc); @@ -2534,7 +2575,6 @@ static int cxlflash_probe(struct pci_dev *pdev, host->max_id = CXLFLASH_MAX_NUM_TARGETS_PER_BUS; host->max_lun = CXLFLASH_MAX_NUM_LUNS_PER_TARGET; - host->max_channel = PORTNUM2CHAN(NUM_FC_PORTS); host->unique_id = host->host_no; host->max_cmd_len = CXLFLASH_MAX_CDB_LEN; @@ -2550,7 +2590,6 @@ static int cxlflash_probe(struct pci_dev *pdev, cfg->init_state = INIT_STATE_NONE; cfg->dev = pdev; - cfg->num_fc_ports = NUM_FC_PORTS; cfg->cxl_fops = cxlflash_cxl_fops; /* |