*/
static void process_cmd_err(struct afu_cmd *cmd, struct scsi_cmnd *scp)
{
+ struct afu *afu = cmd->parent;
+ struct cxlflash_cfg *cfg = afu->parent;
+ struct device *dev = &cfg->dev->dev;
struct sisl_ioarcb *ioarcb;
struct sisl_ioasa *ioasa;
u32 resid;
if (ioasa->rc.flags & SISL_RC_FLAGS_UNDERRUN) {
resid = ioasa->resid;
scsi_set_resid(scp, resid);
- pr_debug("%s: cmd underrun cmd = %p scp = %p, resid = %d\n",
- __func__, cmd, scp, resid);
+ dev_dbg(dev, "%s: cmd underrun cmd = %p scp = %p, resid = %d\n",
+ __func__, cmd, scp, resid);
}
if (ioasa->rc.flags & SISL_RC_FLAGS_OVERRUN) {
- pr_debug("%s: cmd underrun cmd = %p scp = %p\n",
- __func__, cmd, scp);
+ dev_dbg(dev, "%s: cmd underrun cmd = %p scp = %p\n",
+ __func__, cmd, scp);
scp->result = (DID_ERROR << 16);
}
- pr_debug("%s: cmd failed afu_rc=%d scsi_rc=%d fc_rc=%d "
- "afu_extra=0x%X, scsi_extra=0x%X, fc_extra=0x%X\n",
- __func__, ioasa->rc.afu_rc, ioasa->rc.scsi_rc,
- ioasa->rc.fc_rc, ioasa->afu_extra, ioasa->scsi_extra,
- ioasa->fc_extra);
+ dev_dbg(dev, "%s: cmd failed afu_rc=%02x scsi_rc=%02x fc_rc=%02x "
+ "afu_extra=%02x scsi_extra=%02x fc_extra=%02x\n", __func__,
+ ioasa->rc.afu_rc, ioasa->rc.scsi_rc, ioasa->rc.fc_rc,
+ ioasa->afu_extra, ioasa->scsi_extra, ioasa->fc_extra);
if (ioasa->rc.scsi_rc) {
/* We have a SCSI status */
ulong lock_flags;
struct afu *afu = cmd->parent;
struct cxlflash_cfg *cfg = afu->parent;
+ struct device *dev = &cfg->dev->dev;
bool cmd_is_tmf;
if (cmd->scp) {
cmd_is_tmf = cmd->cmd_tmf;
- pr_debug_ratelimited("%s: calling scsi_done scp=%p result=%X "
- "ioasc=%d\n", __func__, scp, scp->result,
- cmd->sa.ioasc);
+ dev_dbg_ratelimited(dev, "%s:scp=%p result=%08x ioasc=%08x\n",
+ __func__, scp, scp->result, cmd->sa.ioasc);
scsi_dma_unmap(scp);
scp->scsi_done(scp);
}
/**
- * context_reset_ioarrin() - reset command owner context via IOARRIN register
+ * context_reset() - reset command owner context via specified register
* @cmd: AFU command that timed out.
+ * @reset_reg: MMIO register to perform reset.
*/
-static void context_reset_ioarrin(struct afu_cmd *cmd)
+static void context_reset(struct afu_cmd *cmd, __be64 __iomem *reset_reg)
{
int nretry = 0;
u64 rrin = 0x1;
struct cxlflash_cfg *cfg = afu->parent;
struct device *dev = &cfg->dev->dev;
- pr_debug("%s: cmd=%p\n", __func__, cmd);
+ dev_dbg(dev, "%s: cmd=%p\n", __func__, cmd);
- writeq_be(rrin, &afu->host_map->ioarrin);
+ writeq_be(rrin, reset_reg);
do {
- rrin = readq_be(&afu->host_map->ioarrin);
+ rrin = readq_be(reset_reg);
if (rrin != 0x1)
break;
/* Double delay each time */
udelay(1 << nretry);
} while (nretry++ < MC_ROOM_RETRY_CNT);
- dev_dbg(dev, "%s: returning rrin=0x%016llX nretry=%d\n",
+ dev_dbg(dev, "%s: returning rrin=%016llx nretry=%d\n",
__func__, rrin, nretry);
}
+/**
+ * context_reset_ioarrin() - reset command owner context via IOARRIN register
+ * @cmd: AFU command that timed out.
+ */
+static void context_reset_ioarrin(struct afu_cmd *cmd)
+{
+ struct afu *afu = cmd->parent;
+
+ context_reset(cmd, &afu->host_map->ioarrin);
+}
+
+/**
+ * context_reset_sq() - reset command owner context w/ SQ Context Reset register
+ * @cmd: AFU command that timed out.
+ */
+static void context_reset_sq(struct afu_cmd *cmd)
+{
+ struct afu *afu = cmd->parent;
+
+ context_reset(cmd, &afu->host_map->sq_ctx_reset);
+}
+
/**
* send_cmd_ioarrin() - sends an AFU command via IOARRIN register
* @afu: AFU associated with the host.
writeq_be((u64)&cmd->rcb, &afu->host_map->ioarrin);
out:
spin_unlock_irqrestore(&afu->rrin_slock, lock_flags);
- pr_devel("%s: cmd=%p len=%d ea=%p rc=%d\n", __func__, cmd,
- cmd->rcb.data_len, (void *)cmd->rcb.data_ea, rc);
+ dev_dbg(dev, "%s: cmd=%p len=%u ea=%016llx rc=%d\n", __func__,
+ cmd, cmd->rcb.data_len, cmd->rcb.data_ea, rc);
+ return rc;
+}
+
+/**
+ * send_cmd_sq() - sends an AFU command via SQ ring
+ * @afu: AFU associated with the host.
+ * @cmd: AFU command to send.
+ *
+ * Return:
+ * 0 on success, SCSI_MLQUEUE_HOST_BUSY on failure
+ */
+static int send_cmd_sq(struct afu *afu, struct afu_cmd *cmd)
+{
+ struct cxlflash_cfg *cfg = afu->parent;
+ struct device *dev = &cfg->dev->dev;
+ int rc = 0;
+ int newval;
+ ulong lock_flags;
+
+ newval = atomic_dec_if_positive(&afu->hsq_credits);
+ if (newval <= 0) {
+ rc = SCSI_MLQUEUE_HOST_BUSY;
+ goto out;
+ }
+
+ cmd->rcb.ioasa = &cmd->sa;
+
+ spin_lock_irqsave(&afu->hsq_slock, lock_flags);
+
+ *afu->hsq_curr = cmd->rcb;
+ if (afu->hsq_curr < afu->hsq_end)
+ afu->hsq_curr++;
+ else
+ afu->hsq_curr = afu->hsq_start;
+ writeq_be((u64)afu->hsq_curr, &afu->host_map->sq_tail);
+
+ spin_unlock_irqrestore(&afu->hsq_slock, lock_flags);
+out:
+ dev_dbg(dev, "%s: cmd=%p len=%u ea=%016llx ioasa=%p rc=%d curr=%p "
+ "head=%016llx tail=%016llx\n", __func__, cmd, cmd->rcb.data_len,
+ cmd->rcb.data_ea, cmd->rcb.ioasa, rc, afu->hsq_curr,
+ readq_be(&afu->host_map->sq_head),
+ readq_be(&afu->host_map->sq_tail));
return rc;
}
*/
static int wait_resp(struct afu *afu, struct afu_cmd *cmd)
{
+ struct cxlflash_cfg *cfg = afu->parent;
+ struct device *dev = &cfg->dev->dev;
int rc = 0;
ulong timeout = msecs_to_jiffies(cmd->rcb.timeout * 2 * 1000);
}
if (unlikely(cmd->sa.ioasc != 0)) {
- pr_err("%s: CMD 0x%X failed, IOASC: flags 0x%X, afu_rc 0x%X, "
- "scsi_rc 0x%X, fc_rc 0x%X\n", __func__, cmd->rcb.cdb[0],
- cmd->sa.rc.flags, cmd->sa.rc.afu_rc, cmd->sa.rc.scsi_rc,
- cmd->sa.rc.fc_rc);
+ dev_err(dev, "%s: cmd %02x failed, ioasc=%08x\n",
+ __func__, cmd->rcb.cdb[0], cmd->sa.ioasc);
rc = -1;
}
*/
static int send_tmf(struct afu *afu, struct scsi_cmnd *scp, u64 tmfcmd)
{
- u32 port_sel = scp->device->channel + 1;
- struct Scsi_Host *host = scp->device->host;
- struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)host->hostdata;
+ struct cxlflash_cfg *cfg = shost_priv(scp->device->host);
struct afu_cmd *cmd = sc_to_afucz(scp);
struct device *dev = &cfg->dev->dev;
ulong lock_flags;
cmd->rcb.ctx_id = afu->ctx_hndl;
cmd->rcb.msi = SISL_MSI_RRQ_UPDATED;
- cmd->rcb.port_sel = port_sel;
+ cmd->rcb.port_sel = CHAN2PORTMASK(scp->device->channel);
cmd->rcb.lun_id = lun_to_lunid(scp->device->lun);
cmd->rcb.req_flags = (SISL_REQ_FLAGS_PORT_LUN_ID |
SISL_REQ_FLAGS_SUP_UNDERRUN |
to);
if (!to) {
cfg->tmf_active = false;
- dev_err(dev, "%s: TMF timed out!\n", __func__);
+ dev_err(dev, "%s: TMF timed out\n", __func__);
rc = -1;
}
spin_unlock_irqrestore(&cfg->tmf_slock, lock_flags);
return rc;
}
-static void afu_unmap(struct kref *ref)
-{
- struct afu *afu = container_of(ref, struct afu, mapcount);
-
- if (likely(afu->afu_map)) {
- cxl_psa_unmap((void __iomem *)afu->afu_map);
- afu->afu_map = NULL;
- }
-}
-
/**
* cxlflash_driver_info() - information handler for this host driver
* @host: SCSI host associated with device.
*/
static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp)
{
- struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)host->hostdata;
+ struct cxlflash_cfg *cfg = shost_priv(host);
struct afu *afu = cfg->afu;
struct device *dev = &cfg->dev->dev;
struct afu_cmd *cmd = sc_to_afucz(scp);
struct scatterlist *sg = scsi_sglist(scp);
- u32 port_sel = scp->device->channel + 1;
u16 req_flags = SISL_REQ_FLAGS_SUP_UNDERRUN;
ulong lock_flags;
int nseg = 0;
int rc = 0;
- int kref_got = 0;
dev_dbg_ratelimited(dev, "%s: (scp=%p) %d/%d/%d/%llu "
- "cdb=(%08X-%08X-%08X-%08X)\n",
+ "cdb=(%08x-%08x-%08x-%08x)\n",
__func__, scp, host->host_no, scp->device->channel,
scp->device->id, scp->device->lun,
get_unaligned_be32(&((u32 *)scp->cmnd)[0]),
switch (cfg->state) {
case STATE_RESET:
- dev_dbg_ratelimited(dev, "%s: device is in reset!\n", __func__);
+ dev_dbg_ratelimited(dev, "%s: device is in reset\n", __func__);
rc = SCSI_MLQUEUE_HOST_BUSY;
goto out;
case STATE_FAILTERM:
- dev_dbg_ratelimited(dev, "%s: device has failed!\n", __func__);
+ dev_dbg_ratelimited(dev, "%s: device has failed\n", __func__);
scp->result = (DID_NO_CONNECT << 16);
scp->scsi_done(scp);
rc = 0;
break;
}
- kref_get(&cfg->afu->mapcount);
- kref_got = 1;
-
if (likely(sg)) {
nseg = scsi_dma_map(scp);
if (unlikely(nseg < 0)) {
- dev_err(dev, "%s: Fail DMA map!\n", __func__);
+ dev_err(dev, "%s: Fail DMA map\n", __func__);
rc = SCSI_MLQUEUE_HOST_BUSY;
goto out;
}
cmd->rcb.ctx_id = afu->ctx_hndl;
cmd->rcb.msi = SISL_MSI_RRQ_UPDATED;
- cmd->rcb.port_sel = port_sel;
+ cmd->rcb.port_sel = CHAN2PORTMASK(scp->device->channel);
cmd->rcb.lun_id = lun_to_lunid(scp->device->lun);
if (scp->sc_data_direction == DMA_TO_DEVICE)
if (unlikely(rc))
scsi_dma_unmap(scp);
out:
- if (kref_got)
- kref_put(&afu->mapcount, afu_unmap);
- pr_devel("%s: returning rc=%d\n", __func__, rc);
return rc;
}
*
* Safe to call with AFU in a partially allocated/initialized state.
*
- * Waits for any active internal AFU commands to timeout and then unmaps
- * the MMIO space.
+ * Cancels scheduled worker threads, waits for any active internal AFU
+ * commands to timeout, disables IRQ polling and then unmaps the MMIO space.
*/
static void stop_afu(struct cxlflash_cfg *cfg)
{
struct afu *afu = cfg->afu;
+ cancel_work_sync(&cfg->work_q);
+
if (likely(afu)) {
while (atomic_read(&afu->cmds_active))
ssleep(1);
+ if (afu_is_irqpoll_enabled(afu))
+ irq_poll_disable(&afu->irqpoll);
if (likely(afu->afu_map)) {
cxl_psa_unmap((void __iomem *)afu->afu_map);
afu->afu_map = NULL;
}
- kref_put(&afu->mapcount, afu_unmap);
}
}
*/
static void term_afu(struct cxlflash_cfg *cfg)
{
+ struct device *dev = &cfg->dev->dev;
+
/*
* Tear down is carefully orchestrated to ensure
* no interrupts can come in when the problem state
term_mc(cfg);
- pr_debug("%s: returning\n", __func__);
+ dev_dbg(dev, "%s: returning\n", __func__);
}
/**
{
struct afu *afu = cfg->afu;
struct device *dev = &cfg->dev->dev;
- struct sisl_global_map __iomem *global;
struct dev_dependent_vals *ddv;
+ __be64 __iomem *fc_port_regs;
u64 reg, status;
int i, retry_cnt = 0;
return;
if (!afu || !afu->afu_map) {
- dev_dbg(dev, "%s: The problem state area is not mapped\n",
- __func__);
+ dev_dbg(dev, "%s: Problem state area not mapped\n", __func__);
return;
}
- global = &afu->afu_map->global;
-
/* Notify AFU */
- for (i = 0; i < NUM_FC_PORTS; i++) {
- reg = readq_be(&global->fc_regs[i][FC_CONFIG2 / 8]);
+ for (i = 0; i < cfg->num_fc_ports; i++) {
+ fc_port_regs = get_fc_port_regs(cfg, i);
+
+ reg = readq_be(&fc_port_regs[FC_CONFIG2 / 8]);
reg |= SISL_FC_SHUTDOWN_NORMAL;
- writeq_be(reg, &global->fc_regs[i][FC_CONFIG2 / 8]);
+ writeq_be(reg, &fc_port_regs[FC_CONFIG2 / 8]);
}
if (!wait)
return;
/* Wait up to 1.5 seconds for shutdown processing to complete */
- for (i = 0; i < NUM_FC_PORTS; i++) {
+ for (i = 0; i < cfg->num_fc_ports; i++) {
+ fc_port_regs = get_fc_port_regs(cfg, i);
retry_cnt = 0;
+
while (true) {
- status = readq_be(&global->fc_regs[i][FC_STATUS / 8]);
+ status = readq_be(&fc_port_regs[FC_STATUS / 8]);
if (status & SISL_STATUS_SHUTDOWN_COMPLETE)
break;
if (++retry_cnt >= MC_RETRY_CNT) {
static void cxlflash_remove(struct pci_dev *pdev)
{
struct cxlflash_cfg *cfg = pci_get_drvdata(pdev);
+ struct device *dev = &pdev->dev;
ulong lock_flags;
if (!pci_is_enabled(pdev)) {
- pr_debug("%s: Device is disabled\n", __func__);
+ dev_dbg(dev, "%s: Device is disabled\n", __func__);
return;
}
scsi_remove_host(cfg->host);
/* fall through */
case INIT_STATE_AFU:
- cancel_work_sync(&cfg->work_q);
term_afu(cfg);
case INIT_STATE_PCI:
pci_disable_device(pdev);
break;
}
- pr_debug("%s: returning\n", __func__);
+ dev_dbg(dev, "%s: returning\n", __func__);
}
/**
int rc = 0;
struct device *dev = &cfg->dev->dev;
- /* AFU is ~12k, i.e. only one 64k page or up to four 4k pages */
+ /* AFU is ~28k, i.e. only one 64k page or up to seven 4k pages */
cfg->afu = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
get_order(sizeof(struct afu)));
if (unlikely(!cfg->afu)) {
static int init_pci(struct cxlflash_cfg *cfg)
{
struct pci_dev *pdev = cfg->dev;
+ struct device *dev = &cfg->dev->dev;
int rc = 0;
rc = pci_enable_device(pdev);
}
if (rc) {
- dev_err(&pdev->dev, "%s: Cannot enable adapter\n",
- __func__);
+ dev_err(dev, "%s: Cannot enable adapter\n", __func__);
cxlflash_wait_for_pci_err_recovery(cfg);
goto out;
}
}
out:
- pr_debug("%s: returning rc=%d\n", __func__, rc);
+ dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc);
return rc;
}
static int init_scsi(struct cxlflash_cfg *cfg)
{
struct pci_dev *pdev = cfg->dev;
+ struct device *dev = &cfg->dev->dev;
int rc = 0;
rc = scsi_add_host(cfg->host, &pdev->dev);
if (rc) {
- dev_err(&pdev->dev, "%s: scsi_add_host failed (rc=%d)\n",
- __func__, rc);
+ dev_err(dev, "%s: scsi_add_host failed rc=%d\n", __func__, rc);
goto out;
}
scsi_scan_host(cfg->host);
out:
- pr_debug("%s: returning rc=%d\n", __func__, rc);
+ dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc);
return rc;
}
* Return:
* TRUE (1) when the specified port is online
* FALSE (0) when the specified port fails to come online after timeout
- * -EINVAL when @delay_us is less than 1000
*/
-static int wait_port_online(__be64 __iomem *fc_regs, u32 delay_us, u32 nretry)
+static bool wait_port_online(__be64 __iomem *fc_regs, u32 delay_us, u32 nretry)
{
u64 status;
- if (delay_us < 1000) {
- pr_err("%s: invalid delay specified %d\n", __func__, delay_us);
- return -EINVAL;
- }
+ WARN_ON(delay_us < 1000);
do {
msleep(delay_us / 1000);
* Return:
* TRUE (1) when the specified port is offline
* FALSE (0) when the specified port fails to go offline after timeout
- * -EINVAL when @delay_us is less than 1000
*/
-static int wait_port_offline(__be64 __iomem *fc_regs, u32 delay_us, u32 nretry)
+static bool wait_port_offline(__be64 __iomem *fc_regs, u32 delay_us, u32 nretry)
{
u64 status;
- if (delay_us < 1000) {
- pr_err("%s: invalid delay specified %d\n", __func__, delay_us);
- return -EINVAL;
- }
+ WARN_ON(delay_us < 1000);
do {
msleep(delay_us / 1000);
static void afu_set_wwpn(struct afu *afu, int port, __be64 __iomem *fc_regs,
u64 wwpn)
{
+ struct cxlflash_cfg *cfg = afu->parent;
+ struct device *dev = &cfg->dev->dev;
+
set_port_offline(fc_regs);
if (!wait_port_offline(fc_regs, FC_PORT_STATUS_RETRY_INTERVAL_US,
FC_PORT_STATUS_RETRY_CNT)) {
- pr_debug("%s: wait on port %d to go offline timed out\n",
- __func__, port);
+ dev_dbg(dev, "%s: wait on port %d to go offline timed out\n",
+ __func__, port);
}
writeq_be(wwpn, &fc_regs[FC_PNAME / 8]);
set_port_online(fc_regs);
if (!wait_port_online(fc_regs, FC_PORT_STATUS_RETRY_INTERVAL_US,
FC_PORT_STATUS_RETRY_CNT)) {
- pr_debug("%s: wait on port %d to go online timed out\n",
- __func__, port);
+ dev_dbg(dev, "%s: wait on port %d to go online timed out\n",
+ __func__, port);
}
}
*/
static void afu_link_reset(struct afu *afu, int port, __be64 __iomem *fc_regs)
{
+ struct cxlflash_cfg *cfg = afu->parent;
+ struct device *dev = &cfg->dev->dev;
u64 port_sel;
/* first switch the AFU to the other links, if any */
set_port_offline(fc_regs);
if (!wait_port_offline(fc_regs, FC_PORT_STATUS_RETRY_INTERVAL_US,
FC_PORT_STATUS_RETRY_CNT))
- pr_err("%s: wait on port %d to go offline timed out\n",
- __func__, port);
+ dev_err(dev, "%s: wait on port %d to go offline timed out\n",
+ __func__, port);
set_port_online(fc_regs);
if (!wait_port_online(fc_regs, FC_PORT_STATUS_RETRY_INTERVAL_US,
FC_PORT_STATUS_RETRY_CNT))
- pr_err("%s: wait on port %d to go online timed out\n",
- __func__, port);
+ dev_err(dev, "%s: wait on port %d to go online timed out\n",
+ __func__, port);
/* switch back to include this port */
port_sel |= (1ULL << port);
writeq_be(port_sel, &afu->afu_map->global.regs.afu_port_sel);
cxlflash_afu_sync(afu, 0, 0, AFU_GSYNC);
- pr_debug("%s: returning port_sel=%lld\n", __func__, port_sel);
+ dev_dbg(dev, "%s: returning port_sel=%016llx\n", __func__, port_sel);
}
/*
*/
static void afu_err_intr_init(struct afu *afu)
{
+ struct cxlflash_cfg *cfg = afu->parent;
+ __be64 __iomem *fc_port_regs;
int i;
u64 reg;
writeq_be(-1ULL, &afu->afu_map->global.regs.aintr_clear);
/* Clear/Set internal lun bits */
- reg = readq_be(&afu->afu_map->global.fc_regs[0][FC_CONFIG2 / 8]);
+ fc_port_regs = get_fc_port_regs(cfg, 0);
+ reg = readq_be(&fc_port_regs[FC_CONFIG2 / 8]);
reg &= SISL_FC_INTERNAL_MASK;
if (afu->internal_lun)
reg |= ((u64)(afu->internal_lun - 1) << SISL_FC_INTERNAL_SHIFT);
- writeq_be(reg, &afu->afu_map->global.fc_regs[0][FC_CONFIG2 / 8]);
+ writeq_be(reg, &fc_port_regs[FC_CONFIG2 / 8]);
/* now clear FC errors */
- for (i = 0; i < NUM_FC_PORTS; i++) {
- writeq_be(0xFFFFFFFFU,
- &afu->afu_map->global.fc_regs[i][FC_ERROR / 8]);
- writeq_be(0, &afu->afu_map->global.fc_regs[i][FC_ERRCAP / 8]);
+ for (i = 0; i < cfg->num_fc_ports; i++) {
+ fc_port_regs = get_fc_port_regs(cfg, i);
+
+ writeq_be(0xFFFFFFFFU, &fc_port_regs[FC_ERROR / 8]);
+ writeq_be(0, &fc_port_regs[FC_ERRCAP / 8]);
}
/* sync interrupts for master's IOARRIN write */
static irqreturn_t cxlflash_sync_err_irq(int irq, void *data)
{
struct afu *afu = (struct afu *)data;
+ struct cxlflash_cfg *cfg = afu->parent;
+ struct device *dev = &cfg->dev->dev;
u64 reg;
u64 reg_unmasked;
reg_unmasked = (reg & SISL_ISTATUS_UNMASK);
if (reg_unmasked == 0UL) {
- pr_err("%s: %llX: spurious interrupt, intr_status %016llX\n",
- __func__, (u64)afu, reg);
+ dev_err(dev, "%s: spurious interrupt, intr_status=%016llx\n",
+ __func__, reg);
goto cxlflash_sync_err_irq_exit;
}
- pr_err("%s: %llX: unexpected interrupt, intr_status %016llX\n",
- __func__, (u64)afu, reg);
+ dev_err(dev, "%s: unexpected interrupt, intr_status=%016llx\n",
+ __func__, reg);
writeq_be(reg_unmasked, &afu->host_map->intr_clear);
cxlflash_sync_err_irq_exit:
- pr_debug("%s: returning rc=%d\n", __func__, IRQ_HANDLED);
return IRQ_HANDLED;
}
/**
- * cxlflash_rrq_irq() - interrupt handler for read-response queue (normal path)
- * @irq: Interrupt number.
- * @data: Private data provided at interrupt registration, the AFU.
+ * process_hrrq() - process the read-response queue
+ * @afu: AFU associated with the host.
+ * @doneq: Queue of commands harvested from the RRQ.
+ * @budget: Threshold of RRQ entries to process.
*
- * Return: Always return IRQ_HANDLED.
+ * This routine must be called holding the disabled RRQ spin lock.
+ *
+ * Return: The number of entries processed.
*/
-static irqreturn_t cxlflash_rrq_irq(int irq, void *data)
+static int process_hrrq(struct afu *afu, struct list_head *doneq, int budget)
{
- struct afu *afu = (struct afu *)data;
struct afu_cmd *cmd;
+ struct sisl_ioasa *ioasa;
+ struct sisl_ioarcb *ioarcb;
bool toggle = afu->toggle;
+ int num_hrrq = 0;
u64 entry,
*hrrq_start = afu->hrrq_start,
*hrrq_end = afu->hrrq_end,
*hrrq_curr = afu->hrrq_curr;
- /* Process however many RRQ entries that are ready */
+ /* Process ready RRQ entries up to the specified budget (if any) */
while (true) {
entry = *hrrq_curr;
if ((entry & SISL_RESP_HANDLE_T_BIT) != toggle)
break;
- cmd = (struct afu_cmd *)(entry & ~SISL_RESP_HANDLE_T_BIT);
- cmd_complete(cmd);
+ entry &= ~SISL_RESP_HANDLE_T_BIT;
+
+ if (afu_is_sq_cmd_mode(afu)) {
+ ioasa = (struct sisl_ioasa *)entry;
+ cmd = container_of(ioasa, struct afu_cmd, sa);
+ } else {
+ ioarcb = (struct sisl_ioarcb *)entry;
+ cmd = container_of(ioarcb, struct afu_cmd, rcb);
+ }
+
+ list_add_tail(&cmd->queue, doneq);
/* Advance to next entry or wrap and flip the toggle bit */
if (hrrq_curr < hrrq_end)
hrrq_curr = hrrq_start;
toggle ^= SISL_RESP_HANDLE_T_BIT;
}
+
+ atomic_inc(&afu->hsq_credits);
+ num_hrrq++;
+
+ if (budget > 0 && num_hrrq >= budget)
+ break;
}
afu->hrrq_curr = hrrq_curr;
afu->toggle = toggle;
+ return num_hrrq;
+}
+
+/**
+ * process_cmd_doneq() - process a queue of harvested RRQ commands
+ * @doneq: Queue of completed commands.
+ *
+ * Note that upon return the queue can no longer be trusted.
+ */
+static void process_cmd_doneq(struct list_head *doneq)
+{
+ struct afu_cmd *cmd, *tmp;
+
+ WARN_ON(list_empty(doneq));
+
+ list_for_each_entry_safe(cmd, tmp, doneq, queue)
+ cmd_complete(cmd);
+}
+
+/**
+ * cxlflash_irqpoll() - process a queue of harvested RRQ commands
+ * @irqpoll: IRQ poll structure associated with queue to poll.
+ * @budget: Threshold of RRQ entries to process per poll.
+ *
+ * Return: The number of entries processed.
+ */
+static int cxlflash_irqpoll(struct irq_poll *irqpoll, int budget)
+{
+ struct afu *afu = container_of(irqpoll, struct afu, irqpoll);
+ unsigned long hrrq_flags;
+ LIST_HEAD(doneq);
+ int num_entries = 0;
+
+ spin_lock_irqsave(&afu->hrrq_slock, hrrq_flags);
+
+ num_entries = process_hrrq(afu, &doneq, budget);
+ if (num_entries < budget)
+ irq_poll_complete(irqpoll);
+
+ spin_unlock_irqrestore(&afu->hrrq_slock, hrrq_flags);
+
+ process_cmd_doneq(&doneq);
+ return num_entries;
+}
+
+/**
+ * cxlflash_rrq_irq() - interrupt handler for read-response queue (normal path)
+ * @irq: Interrupt number.
+ * @data: Private data provided at interrupt registration, the AFU.
+ *
+ * Return: IRQ_HANDLED or IRQ_NONE when no ready entries found.
+ */
+static irqreturn_t cxlflash_rrq_irq(int irq, void *data)
+{
+ struct afu *afu = (struct afu *)data;
+ unsigned long hrrq_flags;
+ LIST_HEAD(doneq);
+ int num_entries = 0;
+
+ spin_lock_irqsave(&afu->hrrq_slock, hrrq_flags);
+
+ if (afu_is_irqpoll_enabled(afu)) {
+ irq_poll_sched(&afu->irqpoll);
+ spin_unlock_irqrestore(&afu->hrrq_slock, hrrq_flags);
+ return IRQ_HANDLED;
+ }
+
+ num_entries = process_hrrq(afu, &doneq, -1);
+ spin_unlock_irqrestore(&afu->hrrq_slock, hrrq_flags);
+
+ if (num_entries == 0)
+ return IRQ_NONE;
+
+ process_cmd_doneq(&doneq);
return IRQ_HANDLED;
}
u64 reg_unmasked;
const struct asyc_intr_info *info;
struct sisl_global_map __iomem *global = &afu->afu_map->global;
+ __be64 __iomem *fc_port_regs;
u64 reg;
u8 port;
int i;
reg_unmasked = (reg & SISL_ASTATUS_UNMASK);
if (reg_unmasked == 0) {
- dev_err(dev, "%s: spurious interrupt, aintr_status 0x%016llX\n",
+ dev_err(dev, "%s: spurious interrupt, aintr_status=%016llx\n",
__func__, reg);
goto out;
}
continue;
port = info->port;
+ fc_port_regs = get_fc_port_regs(cfg, port);
- dev_err(dev, "%s: FC Port %d -> %s, fc_status 0x%08llX\n",
+ dev_err(dev, "%s: FC Port %d -> %s, fc_status=%016llx\n",
__func__, port, info->desc,
- readq_be(&global->fc_regs[port][FC_STATUS / 8]));
+ readq_be(&fc_port_regs[FC_STATUS / 8]));
/*
* Do link reset first, some OTHER errors will set FC_ERROR
__func__, port);
cfg->lr_state = LINK_RESET_REQUIRED;
cfg->lr_port = port;
- kref_get(&cfg->afu->mapcount);
schedule_work(&cfg->work_q);
}
if (info->action & CLR_FC_ERROR) {
- reg = readq_be(&global->fc_regs[port][FC_ERROR / 8]);
+ reg = readq_be(&fc_port_regs[FC_ERROR / 8]);
/*
* Since all errors are unmasked, FC_ERROR and FC_ERRCAP
* should be the same and tracing one is sufficient.
*/
- dev_err(dev, "%s: fc %d: clearing fc_error 0x%08llX\n",
+ dev_err(dev, "%s: fc %d: clearing fc_error=%016llx\n",
__func__, port, reg);
- writeq_be(reg, &global->fc_regs[port][FC_ERROR / 8]);
- writeq_be(0, &global->fc_regs[port][FC_ERRCAP / 8]);
+ writeq_be(reg, &fc_port_regs[FC_ERROR / 8]);
+ writeq_be(0, &fc_port_regs[FC_ERRCAP / 8]);
}
if (info->action & SCAN_HOST) {
atomic_inc(&cfg->scan_host_needed);
- kref_get(&cfg->afu->mapcount);
schedule_work(&cfg->work_q);
}
}
out:
- dev_dbg(dev, "%s: returning IRQ_HANDLED, afu=%p\n", __func__, afu);
return IRQ_HANDLED;
}
*/
static int start_context(struct cxlflash_cfg *cfg)
{
+ struct device *dev = &cfg->dev->dev;
int rc = 0;
rc = cxl_start_context(cfg->mcctx,
cfg->afu->work.work_element_descriptor,
NULL);
- pr_debug("%s: returning rc=%d\n", __func__, rc);
+ dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc);
return rc;
}
/**
* read_vpd() - obtains the WWPNs from VPD
* @cfg: Internal structure associated with the host.
- * @wwpn: Array of size NUM_FC_PORTS to pass back WWPNs
+ * @wwpn: Array of size MAX_FC_PORTS to pass back WWPNs
*
* Return: 0 on success, -errno on failure
*/
static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[])
{
- struct pci_dev *dev = cfg->dev;
+ struct device *dev = &cfg->dev->dev;
+ struct pci_dev *pdev = cfg->dev;
int rc = 0;
int ro_start, ro_size, i, j, k;
ssize_t vpd_size;
char vpd_data[CXLFLASH_VPD_LEN];
char tmp_buf[WWPN_BUF_LEN] = { 0 };
- char *wwpn_vpd_tags[NUM_FC_PORTS] = { "V5", "V6" };
+ char *wwpn_vpd_tags[MAX_FC_PORTS] = { "V5", "V6" };
/* Get the VPD data from the device */
- vpd_size = cxl_read_adapter_vpd(dev, vpd_data, sizeof(vpd_data));
+ vpd_size = cxl_read_adapter_vpd(pdev, vpd_data, sizeof(vpd_data));
if (unlikely(vpd_size <= 0)) {
- dev_err(&dev->dev, "%s: Unable to read VPD (size = %ld)\n",
- __func__, vpd_size);
+ dev_err(dev, "%s: Unable to read VPD (size = %ld)\n",
+ __func__, vpd_size);
rc = -ENODEV;
goto out;
}
ro_start = pci_vpd_find_tag(vpd_data, 0, vpd_size,
PCI_VPD_LRDT_RO_DATA);
if (unlikely(ro_start < 0)) {
- dev_err(&dev->dev, "%s: VPD Read-only data not found\n",
- __func__);
+ dev_err(dev, "%s: VPD Read-only data not found\n", __func__);
rc = -ENODEV;
goto out;
}
j = ro_size;
i = ro_start + PCI_VPD_LRDT_TAG_SIZE;
if (unlikely((i + j) > vpd_size)) {
- pr_debug("%s: Might need to read more VPD (%d > %ld)\n",
- __func__, (i + j), vpd_size);
+ dev_dbg(dev, "%s: Might need to read more VPD (%d > %ld)\n",
+ __func__, (i + j), vpd_size);
ro_size = vpd_size - i;
}
* because the conversion service requires that the ASCII
* string be terminated.
*/
- for (k = 0; k < NUM_FC_PORTS; k++) {
+ for (k = 0; k < cfg->num_fc_ports; k++) {
j = ro_size;
i = ro_start + PCI_VPD_LRDT_TAG_SIZE;
i = pci_vpd_find_info_keyword(vpd_data, i, j, wwpn_vpd_tags[k]);
if (unlikely(i < 0)) {
- dev_err(&dev->dev, "%s: Port %d WWPN not found "
- "in VPD\n", __func__, k);
+ dev_err(dev, "%s: Port %d WWPN not found in VPD\n",
+ __func__, k);
rc = -ENODEV;
goto out;
}
j = pci_vpd_info_field_size(&vpd_data[i]);
i += PCI_VPD_INFO_FLD_HDR_SIZE;
if (unlikely((i + j > vpd_size) || (j != WWPN_LEN))) {
- dev_err(&dev->dev, "%s: Port %d WWPN incomplete or "
- "VPD corrupt\n",
- __func__, k);
+ dev_err(dev, "%s: Port %d WWPN incomplete or bad VPD\n",
+ __func__, k);
rc = -ENODEV;
goto out;
}
memcpy(tmp_buf, &vpd_data[i], WWPN_LEN);
rc = kstrtoul(tmp_buf, WWPN_LEN, (ulong *)&wwpn[k]);
if (unlikely(rc)) {
- dev_err(&dev->dev, "%s: Fail to convert port %d WWPN "
- "to integer\n", __func__, k);
+ dev_err(dev, "%s: WWPN conversion failed for port %d\n",
+ __func__, k);
rc = -ENODEV;
goto out;
}
+
+ dev_dbg(dev, "%s: wwpn%d=%016llx\n", __func__, k, wwpn[k]);
}
out:
- pr_debug("%s: returning rc=%d\n", __func__, rc);
+ dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc);
return rc;
}
{
struct afu *afu = cfg->afu;
struct device *dev = &cfg->dev->dev;
- u64 wwpn[NUM_FC_PORTS]; /* wwpn of AFU ports */
+ __be64 __iomem *fc_port_regs;
+ u64 wwpn[MAX_FC_PORTS]; /* wwpn of AFU ports */
int i = 0, num_ports = 0;
int rc = 0;
u64 reg;
goto out;
}
- pr_debug("%s: wwpn0=0x%llX wwpn1=0x%llX\n", __func__, wwpn[0], wwpn[1]);
-
- /* Set up RRQ in AFU for master issued cmds */
+ /* Set up RRQ and SQ in AFU for master issued cmds */
writeq_be((u64) afu->hrrq_start, &afu->host_map->rrq_start);
writeq_be((u64) afu->hrrq_end, &afu->host_map->rrq_end);
+ if (afu_is_sq_cmd_mode(afu)) {
+ writeq_be((u64)afu->hsq_start, &afu->host_map->sq_start);
+ writeq_be((u64)afu->hsq_end, &afu->host_map->sq_end);
+ }
+
/* AFU configuration */
reg = readq_be(&afu->afu_map->global.regs.afu_config);
reg |= SISL_AFUCONF_AR_ALL|SISL_AFUCONF_ENDIAN;
if (afu->internal_lun) {
/* Only use port 0 */
writeq_be(PORT0, &afu->afu_map->global.regs.afu_port_sel);
- num_ports = NUM_FC_PORTS - 1;
+ num_ports = 0;
} else {
- writeq_be(BOTH_PORTS, &afu->afu_map->global.regs.afu_port_sel);
- num_ports = NUM_FC_PORTS;
+ writeq_be(PORT_MASK(cfg->num_fc_ports),
+ &afu->afu_map->global.regs.afu_port_sel);
+ num_ports = cfg->num_fc_ports;
}
for (i = 0; i < num_ports; i++) {
+ fc_port_regs = get_fc_port_regs(cfg, i);
+
/* Unmask all errors (but they are still masked at AFU) */
- writeq_be(0, &afu->afu_map->global.fc_regs[i][FC_ERRMSK / 8]);
+ writeq_be(0, &fc_port_regs[FC_ERRMSK / 8]);
/* Clear CRC error cnt & set a threshold */
- (void)readq_be(&afu->afu_map->global.
- fc_regs[i][FC_CNT_CRCERR / 8]);
- writeq_be(MC_CRC_THRESH, &afu->afu_map->global.fc_regs[i]
- [FC_CRC_THRESH / 8]);
+ (void)readq_be(&fc_port_regs[FC_CNT_CRCERR / 8]);
+ writeq_be(MC_CRC_THRESH, &fc_port_regs[FC_CRC_THRESH / 8]);
/* Set WWPNs. If already programmed, wwpn[i] is 0 */
if (wwpn[i] != 0)
- afu_set_wwpn(afu, i,
- &afu->afu_map->global.fc_regs[i][0],
- wwpn[i]);
+ afu_set_wwpn(afu, i, &fc_port_regs[0], wwpn[i]);
/* Programming WWPN back to back causes additional
* offline/online transitions and a PLOGI
*/
&afu->ctrl_map->ctx_cap);
/* Initialize heartbeat */
afu->hb = readq_be(&afu->afu_map->global.regs.afu_hb);
-
out:
return rc;
}
static int start_afu(struct cxlflash_cfg *cfg)
{
struct afu *afu = cfg->afu;
+ struct device *dev = &cfg->dev->dev;
int rc = 0;
init_pcr(cfg);
- /* After an AFU reset, RRQ entries are stale, clear them */
+ /* Initialize RRQ */
memset(&afu->rrq_entry, 0, sizeof(afu->rrq_entry));
-
- /* Initialize RRQ pointers */
afu->hrrq_start = &afu->rrq_entry[0];
afu->hrrq_end = &afu->rrq_entry[NUM_RRQ_ENTRY - 1];
afu->hrrq_curr = afu->hrrq_start;
afu->toggle = 1;
+ spin_lock_init(&afu->hrrq_slock);
+
+ /* Initialize SQ */
+ if (afu_is_sq_cmd_mode(afu)) {
+ memset(&afu->sq, 0, sizeof(afu->sq));
+ afu->hsq_start = &afu->sq[0];
+ afu->hsq_end = &afu->sq[NUM_SQ_ENTRY - 1];
+ afu->hsq_curr = afu->hsq_start;
+
+ spin_lock_init(&afu->hsq_slock);
+ atomic_set(&afu->hsq_credits, NUM_SQ_ENTRY - 1);
+ }
+
+ /* Initialize IRQ poll */
+ if (afu_is_irqpoll_enabled(afu))
+ irq_poll_init(&afu->irqpoll, afu->irqpoll_weight,
+ cxlflash_irqpoll);
rc = init_global(cfg);
- pr_debug("%s: returning rc=%d\n", __func__, rc);
+ dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc);
return rc;
}
rc = cxl_allocate_afu_irqs(ctx, 3);
if (unlikely(rc)) {
- dev_err(dev, "%s: call to allocate_afu_irqs failed rc=%d!\n",
+ dev_err(dev, "%s: allocate_afu_irqs failed rc=%d\n",
__func__, rc);
level = UNDO_NOOP;
goto out;
rc = cxl_map_afu_irq(ctx, 1, cxlflash_sync_err_irq, afu,
"SISL_MSI_SYNC_ERROR");
if (unlikely(rc <= 0)) {
- dev_err(dev, "%s: IRQ 1 (SISL_MSI_SYNC_ERROR) map failed!\n",
- __func__);
+ dev_err(dev, "%s: SISL_MSI_SYNC_ERROR map failed\n", __func__);
level = FREE_IRQ;
goto out;
}
rc = cxl_map_afu_irq(ctx, 2, cxlflash_rrq_irq, afu,
"SISL_MSI_RRQ_UPDATED");
if (unlikely(rc <= 0)) {
- dev_err(dev, "%s: IRQ 2 (SISL_MSI_RRQ_UPDATED) map failed!\n",
- __func__);
+ dev_err(dev, "%s: SISL_MSI_RRQ_UPDATED map failed\n", __func__);
level = UNMAP_ONE;
goto out;
}
rc = cxl_map_afu_irq(ctx, 3, cxlflash_async_err_irq, afu,
"SISL_MSI_ASYNC_ERROR");
if (unlikely(rc <= 0)) {
- dev_err(dev, "%s: IRQ 3 (SISL_MSI_ASYNC_ERROR) map failed!\n",
- __func__);
+ dev_err(dev, "%s: SISL_MSI_ASYNC_ERROR map failed\n", __func__);
level = UNMAP_TWO;
goto out;
}
/* During initialization reset the AFU to start from a clean slate */
rc = cxl_afu_reset(cfg->mcctx);
if (unlikely(rc)) {
- dev_err(dev, "%s: initial AFU reset failed rc=%d\n",
- __func__, rc);
+ dev_err(dev, "%s: AFU reset failed rc=%d\n", __func__, rc);
goto ret;
}
level = init_intr(cfg, ctx);
if (unlikely(level)) {
- dev_err(dev, "%s: setting up interrupts failed rc=%d\n",
- __func__, rc);
+ dev_err(dev, "%s: interrupt init failed rc=%d\n", __func__, rc);
goto out;
}
goto out;
}
ret:
- pr_debug("%s: returning rc=%d\n", __func__, rc);
+ dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc);
return rc;
out:
term_intr(cfg, level);
rc = init_mc(cfg);
if (rc) {
- dev_err(dev, "%s: call to init_mc failed, rc=%d!\n",
+ dev_err(dev, "%s: init_mc failed rc=%d\n",
__func__, rc);
goto out;
}
/* Map the entire MMIO space of the AFU */
afu->afu_map = cxl_psa_map(cfg->mcctx);
if (!afu->afu_map) {
- dev_err(dev, "%s: call to cxl_psa_map failed!\n", __func__);
+ dev_err(dev, "%s: cxl_psa_map failed\n", __func__);
rc = -ENOMEM;
goto err1;
}
- kref_init(&afu->mapcount);
/* No byte reverse on reading afu_version or string will be backwards */
reg = readq(&afu->afu_map->global.regs.afu_version);
afu->interface_version =
readq_be(&afu->afu_map->global.regs.interface_version);
if ((afu->interface_version + 1) == 0) {
- pr_err("Back level AFU, please upgrade. AFU version %s "
- "interface version 0x%llx\n", afu->version,
+ dev_err(dev, "Back level AFU, please upgrade. AFU version %s "
+ "interface version %016llx\n", afu->version,
afu->interface_version);
rc = -EINVAL;
- goto err2;
+ goto err1;
}
- afu->send_cmd = send_cmd_ioarrin;
- afu->context_reset = context_reset_ioarrin;
+ if (afu_is_sq_cmd_mode(afu)) {
+ afu->send_cmd = send_cmd_sq;
+ afu->context_reset = context_reset_sq;
+ } else {
+ afu->send_cmd = send_cmd_ioarrin;
+ afu->context_reset = context_reset_ioarrin;
+ }
- pr_debug("%s: afu version %s, interface version 0x%llX\n", __func__,
- afu->version, afu->interface_version);
+ dev_dbg(dev, "%s: afu_ver=%s interface_ver=%016llx\n", __func__,
+ afu->version, afu->interface_version);
rc = start_afu(cfg);
if (rc) {
- dev_err(dev, "%s: call to start_afu failed, rc=%d!\n",
- __func__, rc);
- goto err2;
+ dev_err(dev, "%s: start_afu failed, rc=%d\n", __func__, rc);
+ goto err1;
}
afu_err_intr_init(cfg->afu);
/* Restore the LUN mappings */
cxlflash_restore_luntable(cfg);
out:
- pr_debug("%s: returning rc=%d\n", __func__, rc);
+ dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc);
return rc;
-err2:
- kref_put(&afu->mapcount, afu_unmap);
err1:
term_intr(cfg, UNMAP_THREE);
term_mc(cfg);
static DEFINE_MUTEX(sync_active);
if (cfg->state != STATE_NORMAL) {
- pr_debug("%s: Sync not required! (%u)\n", __func__, cfg->state);
+ dev_dbg(dev, "%s: Sync not required state=%u\n",
+ __func__, cfg->state);
return 0;
}
init_completion(&cmd->cevent);
cmd->parent = afu;
- pr_debug("%s: afu=%p cmd=%p %d\n", __func__, afu, cmd, ctx_hndl_u);
+ dev_dbg(dev, "%s: afu=%p cmd=%p %d\n", __func__, afu, cmd, ctx_hndl_u);
cmd->rcb.req_flags = SISL_REQ_FLAGS_AFU_CMD;
cmd->rcb.ctx_id = afu->ctx_hndl;
atomic_dec(&afu->cmds_active);
mutex_unlock(&sync_active);
kfree(buf);
- pr_debug("%s: returning rc=%d\n", __func__, rc);
+ dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc);
return rc;
}
*/
static int afu_reset(struct cxlflash_cfg *cfg)
{
+ struct device *dev = &cfg->dev->dev;
int rc = 0;
+
/* Stop the context before the reset. Since the context is
* no longer available restart it after the reset is complete
*/
-
term_afu(cfg);
rc = init_afu(cfg);
- pr_debug("%s: returning rc=%d\n", __func__, rc);
+ dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc);
return rc;
}
{
int rc = SUCCESS;
struct Scsi_Host *host = scp->device->host;
- struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)host->hostdata;
+ struct cxlflash_cfg *cfg = shost_priv(host);
+ struct device *dev = &cfg->dev->dev;
struct afu *afu = cfg->afu;
int rcr = 0;
- pr_debug("%s: (scp=%p) %d/%d/%d/%llu "
- "cdb=(%08X-%08X-%08X-%08X)\n", __func__, scp,
- host->host_no, scp->device->channel,
- scp->device->id, scp->device->lun,
- get_unaligned_be32(&((u32 *)scp->cmnd)[0]),
- get_unaligned_be32(&((u32 *)scp->cmnd)[1]),
- get_unaligned_be32(&((u32 *)scp->cmnd)[2]),
- get_unaligned_be32(&((u32 *)scp->cmnd)[3]));
+ dev_dbg(dev, "%s: (scp=%p) %d/%d/%d/%llu "
+ "cdb=(%08x-%08x-%08x-%08x)\n", __func__, scp, host->host_no,
+ scp->device->channel, scp->device->id, scp->device->lun,
+ get_unaligned_be32(&((u32 *)scp->cmnd)[0]),
+ get_unaligned_be32(&((u32 *)scp->cmnd)[1]),
+ get_unaligned_be32(&((u32 *)scp->cmnd)[2]),
+ get_unaligned_be32(&((u32 *)scp->cmnd)[3]));
retry:
switch (cfg->state) {
break;
}
- pr_debug("%s: returning rc=%d\n", __func__, rc);
+ dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc);
return rc;
}
int rc = SUCCESS;
int rcr = 0;
struct Scsi_Host *host = scp->device->host;
- struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)host->hostdata;
+ struct cxlflash_cfg *cfg = shost_priv(host);
+ struct device *dev = &cfg->dev->dev;
- pr_debug("%s: (scp=%p) %d/%d/%d/%llu "
- "cdb=(%08X-%08X-%08X-%08X)\n", __func__, scp,
- host->host_no, scp->device->channel,
- scp->device->id, scp->device->lun,
- get_unaligned_be32(&((u32 *)scp->cmnd)[0]),
- get_unaligned_be32(&((u32 *)scp->cmnd)[1]),
- get_unaligned_be32(&((u32 *)scp->cmnd)[2]),
- get_unaligned_be32(&((u32 *)scp->cmnd)[3]));
+ dev_dbg(dev, "%s: (scp=%p) %d/%d/%d/%llu "
+ "cdb=(%08x-%08x-%08x-%08x)\n", __func__, scp, host->host_no,
+ scp->device->channel, scp->device->id, scp->device->lun,
+ get_unaligned_be32(&((u32 *)scp->cmnd)[0]),
+ get_unaligned_be32(&((u32 *)scp->cmnd)[1]),
+ get_unaligned_be32(&((u32 *)scp->cmnd)[2]),
+ get_unaligned_be32(&((u32 *)scp->cmnd)[3]));
switch (cfg->state) {
case STATE_NORMAL:
break;
}
- pr_debug("%s: returning rc=%d\n", __func__, rc);
+ dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc);
return rc;
}
/**
* cxlflash_show_port_status() - queries and presents the current port status
* @port: Desired port for status reporting.
- * @afu: AFU owning the specified port.
+ * @cfg: Internal structure associated with the host.
* @buf: Buffer of length PAGE_SIZE to report back port status in ASCII.
*
- * Return: The size of the ASCII string returned in @buf.
+ * Return: The size of the ASCII string returned in @buf or -EINVAL.
*/
-static ssize_t cxlflash_show_port_status(u32 port, struct afu *afu, char *buf)
+static ssize_t cxlflash_show_port_status(u32 port,
+ struct cxlflash_cfg *cfg,
+ char *buf)
{
+ struct device *dev = &cfg->dev->dev;
char *disp_status;
u64 status;
- __be64 __iomem *fc_regs;
+ __be64 __iomem *fc_port_regs;
- if (port >= NUM_FC_PORTS)
- return 0;
+ WARN_ON(port >= MAX_FC_PORTS);
+
+ if (port >= cfg->num_fc_ports) {
+ dev_info(dev, "%s: Port %d not supported on this card.\n",
+ __func__, port);
+ return -EINVAL;
+ }
- fc_regs = &afu->afu_map->global.fc_regs[port][0];
- status = readq_be(&fc_regs[FC_MTIP_STATUS / 8]);
+ fc_port_regs = get_fc_port_regs(cfg, port);
+ status = readq_be(&fc_port_regs[FC_MTIP_STATUS / 8]);
status &= FC_MTIP_STATUS_MASK;
if (status == FC_MTIP_STATUS_ONLINE)
struct device_attribute *attr,
char *buf)
{
- struct Scsi_Host *shost = class_to_shost(dev);
- struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata;
- struct afu *afu = cfg->afu;
+ struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev));
- return cxlflash_show_port_status(0, afu, buf);
+ return cxlflash_show_port_status(0, cfg, buf);
}
/**
struct device_attribute *attr,
char *buf)
{
- struct Scsi_Host *shost = class_to_shost(dev);
- struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata;
- struct afu *afu = cfg->afu;
+ struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev));
- return cxlflash_show_port_status(1, afu, buf);
+ return cxlflash_show_port_status(1, cfg, buf);
}
/**
static ssize_t lun_mode_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct Scsi_Host *shost = class_to_shost(dev);
- struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata;
+ struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev));
struct afu *afu = cfg->afu;
return scnprintf(buf, PAGE_SIZE, "%u\n", afu->internal_lun);
const char *buf, size_t count)
{
struct Scsi_Host *shost = class_to_shost(dev);
- struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata;
+ struct cxlflash_cfg *cfg = shost_priv(shost);
struct afu *afu = cfg->afu;
int rc;
u32 lun_mode;
/*
* When configured for internal LUN, there is only one channel,
- * channel number 0, else there will be 2 (default).
+ * channel number 0, else there will be one less than the number
+ * of fc ports for this card.
*/
if (afu->internal_lun)
shost->max_channel = 0;
else
- shost->max_channel = NUM_FC_PORTS - 1;
+ shost->max_channel = PORTNUM2CHAN(cfg->num_fc_ports);
afu_reset(cfg);
scsi_scan_host(cfg->host);
/**
* cxlflash_show_port_lun_table() - queries and presents the port LUN table
* @port: Desired port for status reporting.
- * @afu: AFU owning the specified port.
+ * @cfg: Internal structure associated with the host.
* @buf: Buffer of length PAGE_SIZE to report back port status in ASCII.
*
- * Return: The size of the ASCII string returned in @buf.
+ * Return: The size of the ASCII string returned in @buf or -EINVAL.
*/
static ssize_t cxlflash_show_port_lun_table(u32 port,
- struct afu *afu,
+ struct cxlflash_cfg *cfg,
char *buf)
{
+ struct device *dev = &cfg->dev->dev;
+ __be64 __iomem *fc_port_luns;
int i;
ssize_t bytes = 0;
- __be64 __iomem *fc_port;
- if (port >= NUM_FC_PORTS)
- return 0;
+ WARN_ON(port >= MAX_FC_PORTS);
- fc_port = &afu->afu_map->global.fc_port[port][0];
+ if (port >= cfg->num_fc_ports) {
+ dev_info(dev, "%s: Port %d not supported on this card.\n",
+ __func__, port);
+ return -EINVAL;
+ }
+
+ fc_port_luns = get_fc_port_luns(cfg, port);
for (i = 0; i < CXLFLASH_NUM_VLUNS; i++)
bytes += scnprintf(buf + bytes, PAGE_SIZE - bytes,
- "%03d: %016llX\n", i, readq_be(&fc_port[i]));
+ "%03d: %016llx\n",
+ i, readq_be(&fc_port_luns[i]));
return bytes;
}
struct device_attribute *attr,
char *buf)
{
- struct Scsi_Host *shost = class_to_shost(dev);
- struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata;
- struct afu *afu = cfg->afu;
+ struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev));
- return cxlflash_show_port_lun_table(0, afu, buf);
+ return cxlflash_show_port_lun_table(0, cfg, buf);
}
/**
struct device_attribute *attr,
char *buf)
{
- struct Scsi_Host *shost = class_to_shost(dev);
- struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata;
+ struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev));
+
+ return cxlflash_show_port_lun_table(1, cfg, buf);
+}
+
+/**
+ * irqpoll_weight_show() - presents the current IRQ poll weight for the host
+ * @dev: Generic device associated with the host.
+ * @attr: Device attribute representing the IRQ poll weight.
+ * @buf: Buffer of length PAGE_SIZE to report back the current IRQ poll
+ * weight in ASCII.
+ *
+ * An IRQ poll weight of 0 indicates polling is disabled.
+ *
+ * Return: The size of the ASCII string returned in @buf.
+ */
+static ssize_t irqpoll_weight_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev));
struct afu *afu = cfg->afu;
- return cxlflash_show_port_lun_table(1, afu, buf);
+ return scnprintf(buf, PAGE_SIZE, "%u\n", afu->irqpoll_weight);
+}
+
+/**
+ * irqpoll_weight_store() - sets the current IRQ poll weight for the host
+ * @dev: Generic device associated with the host.
+ * @attr: Device attribute representing the IRQ poll weight.
+ * @buf: Buffer of length PAGE_SIZE containing the desired IRQ poll
+ * weight in ASCII.
+ * @count: Length of data resizing in @buf.
+ *
+ * An IRQ poll weight of 0 indicates polling is disabled.
+ *
+ * Return: The size of the ASCII string returned in @buf.
+ */
+static ssize_t irqpoll_weight_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev));
+ struct device *cfgdev = &cfg->dev->dev;
+ struct afu *afu = cfg->afu;
+ u32 weight;
+ int rc;
+
+ rc = kstrtouint(buf, 10, &weight);
+ if (rc)
+ return -EINVAL;
+
+ if (weight > 256) {
+ dev_info(cfgdev,
+ "Invalid IRQ poll weight. It must be 256 or less.\n");
+ return -EINVAL;
+ }
+
+ if (weight == afu->irqpoll_weight) {
+ dev_info(cfgdev,
+ "Current IRQ poll weight has the same weight.\n");
+ return -EINVAL;
+ }
+
+ if (afu_is_irqpoll_enabled(afu))
+ irq_poll_disable(&afu->irqpoll);
+
+ afu->irqpoll_weight = weight;
+
+ if (weight > 0)
+ irq_poll_init(&afu->irqpoll, weight, cxlflash_irqpoll);
+
+ return count;
}
/**
static DEVICE_ATTR_RO(ioctl_version);
static DEVICE_ATTR_RO(port0_lun_table);
static DEVICE_ATTR_RO(port1_lun_table);
+static DEVICE_ATTR_RW(irqpoll_weight);
static struct device_attribute *cxlflash_host_attrs[] = {
&dev_attr_port0,
&dev_attr_ioctl_version,
&dev_attr_port0_lun_table,
&dev_attr_port1_lun_table,
+ &dev_attr_irqpoll_weight,
NULL
};
0ULL };
static struct dev_dependent_vals dev_flash_gt_vals = { CXLFLASH_MAX_SECTORS,
CXLFLASH_NOTIFY_SHUTDOWN };
+static struct dev_dependent_vals dev_briard_vals = { CXLFLASH_MAX_SECTORS,
+ CXLFLASH_NOTIFY_SHUTDOWN };
/*
* PCI device binding table
PCI_ANY_ID, PCI_ANY_ID, 0, 0, (kernel_ulong_t)&dev_corsa_vals},
{PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_FLASH_GT,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, (kernel_ulong_t)&dev_flash_gt_vals},
+ {PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_BRIARD,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, (kernel_ulong_t)&dev_briard_vals},
{}
};
work_q);
struct afu *afu = cfg->afu;
struct device *dev = &cfg->dev->dev;
+ __be64 __iomem *fc_port_regs;
int port;
ulong lock_flags;
lock_flags);
/* The reset can block... */
- afu_link_reset(afu, port,
- &afu->afu_map->global.fc_regs[port][0]);
+ fc_port_regs = get_fc_port_regs(cfg, port);
+ afu_link_reset(afu, port, fc_port_regs);
spin_lock_irqsave(cfg->host->host_lock, lock_flags);
}
if (atomic_dec_if_positive(&cfg->scan_host_needed) >= 0)
scsi_scan_host(cfg->host);
- kref_put(&afu->mapcount, afu_unmap);
}
/**
{
struct Scsi_Host *host;
struct cxlflash_cfg *cfg = NULL;
+ struct device *dev = &pdev->dev;
struct dev_dependent_vals *ddv;
int rc = 0;
+ int k;
dev_dbg(&pdev->dev, "%s: Found CXLFLASH with IRQ: %d\n",
__func__, pdev->irq);
host = scsi_host_alloc(&driver_template, sizeof(struct cxlflash_cfg));
if (!host) {
- dev_err(&pdev->dev, "%s: call to scsi_host_alloc failed!\n",
- __func__);
+ dev_err(dev, "%s: scsi_host_alloc failed\n", __func__);
rc = -ENOMEM;
goto out;
}
host->max_id = CXLFLASH_MAX_NUM_TARGETS_PER_BUS;
host->max_lun = CXLFLASH_MAX_NUM_LUNS_PER_TARGET;
- host->max_channel = NUM_FC_PORTS - 1;
+ host->max_channel = PORTNUM2CHAN(NUM_FC_PORTS);
host->unique_id = host->host_no;
host->max_cmd_len = CXLFLASH_MAX_CDB_LEN;
- cfg = (struct cxlflash_cfg *)host->hostdata;
+ cfg = shost_priv(host);
cfg->host = host;
rc = alloc_mem(cfg);
if (rc) {
- dev_err(&pdev->dev, "%s: call to alloc_mem failed!\n",
- __func__);
+ dev_err(dev, "%s: alloc_mem failed\n", __func__);
rc = -ENOMEM;
scsi_host_put(cfg->host);
goto out;
cfg->init_state = INIT_STATE_NONE;
cfg->dev = pdev;
+ cfg->num_fc_ports = NUM_FC_PORTS;
cfg->cxl_fops = cxlflash_cxl_fops;
/*
- * The promoted LUNs move to the top of the LUN table. The rest stay
- * on the bottom half. The bottom half grows from the end
- * (index = 255), whereas the top half grows from the beginning
- * (index = 0).
+ * Promoted LUNs move to the top of the LUN table. The rest stay on
+ * the bottom half. The bottom half grows from the end (index = 255),
+ * whereas the top half grows from the beginning (index = 0).
+ *
+ * Initialize the last LUN index for all possible ports.
*/
- cfg->promote_lun_index = 0;
- cfg->last_lun_index[0] = CXLFLASH_NUM_VLUNS/2 - 1;
- cfg->last_lun_index[1] = CXLFLASH_NUM_VLUNS/2 - 1;
+ cfg->promote_lun_index = 0;
+
+ for (k = 0; k < MAX_FC_PORTS; k++)
+ cfg->last_lun_index[k] = CXLFLASH_NUM_VLUNS/2 - 1;
cfg->dev_id = (struct pci_device_id *)dev_id;
rc = init_pci(cfg);
if (rc) {
- dev_err(&pdev->dev, "%s: call to init_pci "
- "failed rc=%d!\n", __func__, rc);
+ dev_err(dev, "%s: init_pci failed rc=%d\n", __func__, rc);
goto out_remove;
}
cfg->init_state = INIT_STATE_PCI;
rc = init_afu(cfg);
if (rc) {
- dev_err(&pdev->dev, "%s: call to init_afu "
- "failed rc=%d!\n", __func__, rc);
+ dev_err(dev, "%s: init_afu failed rc=%d\n", __func__, rc);
goto out_remove;
}
cfg->init_state = INIT_STATE_AFU;
rc = init_scsi(cfg);
if (rc) {
- dev_err(&pdev->dev, "%s: call to init_scsi "
- "failed rc=%d!\n", __func__, rc);
+ dev_err(dev, "%s: init_scsi failed rc=%d\n", __func__, rc);
goto out_remove;
}
cfg->init_state = INIT_STATE_SCSI;
out:
- pr_debug("%s: returning rc=%d\n", __func__, rc);
+ dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc);
return rc;
out_remove:
drain_ioctls(cfg);
rc = cxlflash_mark_contexts_error(cfg);
if (unlikely(rc))
- dev_err(dev, "%s: Failed to mark user contexts!(%d)\n",
+ dev_err(dev, "%s: Failed to mark user contexts rc=%d\n",
__func__, rc);
term_afu(cfg);
return PCI_ERS_RESULT_NEED_RESET;
rc = init_afu(cfg);
if (unlikely(rc)) {
- dev_err(dev, "%s: EEH recovery failed! (%d)\n", __func__, rc);
+ dev_err(dev, "%s: EEH recovery failed rc=%d\n", __func__, rc);
return PCI_ERS_RESULT_DISCONNECT;
}
*/
static int __init init_cxlflash(void)
{
- pr_info("%s: %s\n", __func__, CXLFLASH_ADAPTER_NAME);
-
cxlflash_list_init();
return pci_register_driver(&cxlflash_driver);