From: Uma Krishnan <hidden> Date: 2016-11-15 23:12:35
The first four patches in this patch series include fixes for command
room violation and lun table management.
The remaining patches remove the reliance upon an internally maintained
private command pool in favor of private commands being allocated
alongside the SCSI commands. Several cleanup opportunities were noticed
while removing the private command pool infrastructure and have been
included as well. Lastly, the final two patches provide staging for
supporting hardware with a different queuing model.
The series is based upon 4.9-rc5, intended for 4.10 and is bisectable.
Matthew R. Ochs (10):
cxlflash: Remove unused buffer from AFU command
cxlflash: Allocate memory instead of using command pool for AFU sync
cxlflash: Use cmd_size for private commands
cxlflash: Remove private command pool
cxlflash: Wait for active AFU commands to timeout upon tear down
cxlflash: Remove AFU command lock
cxlflash: Cleanup send_tmf()
cxlflash: Cleanup queuecommand()
cxlflash: Migrate IOARRIN specific routines to function pointers
cxlflash: Migrate scsi command pointer to AFU command
Uma Krishnan (4):
cxlflash: Set sg_tablesize to 1 instead of SG_NONE
cxlflash: Fix crash in cxlflash_restore_luntable()
cxlflash: Improve context_reset() logic
cxlflash: Avoid command room violation
drivers/scsi/cxlflash/common.h | 35 ++--
drivers/scsi/cxlflash/lunmgt.c | 6 +
drivers/scsi/cxlflash/main.c | 360 +++++++++++-----------------------------
drivers/scsi/cxlflash/sislite.h | 2 +-
4 files changed, 120 insertions(+), 283 deletions(-)
--
2.1.0
From: Uma Krishnan <hidden> Date: 2016-11-15 23:13:52
The following Oops is encountered when blk_mq is enabled with the
cxlflash driver:
[ 2960.817172] Oops: Kernel access of bad area, sig: 11 [#5]
[ 2960.817309] NIP __blk_mq_run_hw_queue+0x278/0x4c0
[ 2960.817313] LR __blk_mq_run_hw_queue+0x2bc/0x4c0
[ 2960.817314] Call Trace:
[ 2960.817320] __blk_mq_run_hw_queue+0x2bc/0x4c0 (unreliable)
[ 2960.817324] blk_mq_run_hw_queue+0xd8/0x100
[ 2960.817329] blk_mq_insert_requests+0x14c/0x1f0
[ 2960.817333] blk_mq_flush_plug_list+0x150/0x190
[ 2960.817338] blk_flush_plug_list+0x11c/0x2b0
[ 2960.817344] blk_finish_plug+0x58/0x80
[ 2960.817348] __do_page_cache_readahead+0x1c0/0x2e0
[ 2960.817352] force_page_cache_readahead+0x68/0xd0
[ 2960.817356] generic_file_read_iter+0x43c/0x6a0
[ 2960.817359] blkdev_read_iter+0x68/0xa0
[ 2960.817361] __vfs_read+0x11c/0x180
[ 2960.817364] vfs_read+0xa4/0x1c0
[ 2960.817366] SyS_read+0x6c/0x110
[ 2960.817369] system_call+0x38/0xb4
The SCSI blk_mq stack assumes that sg_tablesize is always a non-zero
value with scsi_mq_setup_tags() allocating tags using sg_tablesize.
The cxlflash driver currently uses SG_NONE (0) for the sg_tablesize
as the devices it supports are not capable of scatter gather. This
mismatch of values results in the Oops above.
To resolve this issue, sg_tablesize for cxlflash can simply be set
to 1, a value which satisfies the constraints in cxlflash and the
lack of support of SG_NONE in SCSI blk_mq.
Signed-off-by: Uma Krishnan <redacted>
---
drivers/scsi/cxlflash/main.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
@@ -2377,7 +2377,7 @@ static struct scsi_host_template driver_template = {.cmd_per_lun=CXLFLASH_MAX_CMDS_PER_LUN,.can_queue=CXLFLASH_MAX_CMDS,.this_id=-1,-.sg_tablesize=SG_NONE,/* No scatter gather support */+.sg_tablesize=1,/* No scatter gather support */.max_sectors=CXLFLASH_MAX_SECTORS,.use_clustering=ENABLE_CLUSTERING,.shost_attrs=cxlflash_host_attrs,
From: Uma Krishnan <hidden> Date: 2016-11-15 23:14:13
During test, the following crash was observed:
[34538.981505] Faulting instruction address: 0xd000000007c9c870
cpu 0x9: Vector: 300 (Data Access) at [c0000007f1e8f590]
pc: d000000007c9c870: cxlflash_restore_luntable+0x70/0x1d0 [cxlflash]
lr: d000000007c9c84c: cxlflash_restore_luntable+0x4c/0x1d0 [cxlflash]
sp: c0000007f1e8f810
msr: 9000000100009033
dar: c00000171d637438
dsisr: 40000000
current = 0xc0000007f1e43f90
paca = 0xc000000007b25100 softe: 0 irq_happened: 0x01
pid = 493, comm = eehd
enter ? for help
[c0000007f1e8f8a0] d000000007c940b0 init_afu+0xd60/0x1200 [cxlflash]
[c0000007f1e8f9a0] d000000007c945a8 cxlflash_pci_slot_reset+0x58/0xe0 [cxlflash]
[c0000007f1e8fa20] d00000000715f790 cxl_pci_slot_reset+0x230/0x340 [cxl]
[c0000007f1e8fae0] c000000000040dd4 eeh_report_reset+0x144/0x180
[c0000007f1e8fb20] c00000000003f708 eeh_pe_dev_traverse+0x98/0x170
[c0000007f1e8fbb0] c000000000041618 eeh_handle_normal_event+0x328/0x410
[c0000007f1e8fc30] c000000000041db8 eeh_handle_event+0x178/0x330
[c0000007f1e8fce0] c000000000042118 eeh_event_handler+0x1a8/0x1b0
[c0000007f1e8fd80] c00000000011420c kthread+0xec/0x100
[c0000007f1e8fe30] c00000000000a47c ret_from_kernel_thread+0x5c/0xe0
When superpipe mode is disabled for a LUN, the references for the
local lun are deleted but the LUN is still identified as being present
in the LUN table. This mismatched state can result in the above crash
when the LUN table is restored during an error recovery operation.
To fix this issue, the local LUN information structure is updated to
reflect the LUN is no longer in the LUN table once all references to
the LUN are gone.
Signed-off-by: Uma Krishnan <redacted>
---
drivers/scsi/cxlflash/lunmgt.c | 6 ++++++
1 file changed, 6 insertions(+)
From: Uma Krishnan <hidden> Date: 2016-11-15 23:14:26
Currently, the context reset routine waits for command room to
be available before sending the reset request. Per review of the
SISLite specification and clarifications from the CXL Flash AFU
designers, this wait is unnecessary. The reset request can be
sent anytime regardless of command room, so long as only a single
reset request is active at any one point in time.
This commit simplifies the reset routine by removing the wait for
command room. Additionally it adds a debug trace to help pinpoint
hardware errors when a context reset does not complete.
Signed-off-by: Uma Krishnan <redacted>
---
drivers/scsi/cxlflash/main.c | 23 +++++------------------
1 file changed, 5 insertions(+), 18 deletions(-)
From: Uma Krishnan <hidden> Date: 2016-11-15 23:14:35
During test, a command room violation interrupt is occasionally seen
for the master context when the CXL flash devices are stressed.
After studying the code, there could be gaps in the way command room
value is being cached in cxlflash. When the cached command room is zero
the thread attempting to send becomes burdened with updating the cached
value with the actual value from the AFU. Today, this is handled with
an atomic set operation of the raw value read. Following the atomic
update, the thread proceeds to send.
This behavior is incorrect on two counts:
- The update fails to take into account the current thread and its
consumption of one of the hardware commands.
- The update does not take into account other threads also atomically
updating. Per design, a worker thread updates the cached value when
a send thread times out. By not performing an atomic compare/exchange,
the cached value can be incorrectly clobbered.
To correct these issues, the runtime updates of the cached command room
are updated to use atomic64_cmpxchg() and the send routine is updated to
take into account the current thread consuming a hardware command.
Signed-off-by: Uma Krishnan <redacted>
---
drivers/scsi/cxlflash/main.c | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
From: Uma Krishnan <hidden> Date: 2016-11-15 23:14:45
From: "Matthew R. Ochs" <redacted>
The cxlflash driver originally required a per-command 4K buffer that
hosted data passed to the AFU. When the routines that initiate AFU
and internal SCSI commands were refactored to use scsi_execute(), the
need for this buffer became obsolete. As it is no longer necessary,
the buffer is removed.
Signed-off-by: Matthew R. Ochs <redacted>
---
drivers/scsi/cxlflash/common.h | 1 -
drivers/scsi/cxlflash/main.c | 28 ++--------------------------
2 files changed, 2 insertions(+), 27 deletions(-)
@@ -874,7 +864,6 @@ static int alloc_mem(struct cxlflash_cfg *cfg){intrc=0;inti;-char*buf=NULL;structdevice*dev=&cfg->dev->dev;/* AFU is ~12k, i.e. only one 64k page or up to four 4k pages */
From: Uma Krishnan <hidden> Date: 2016-11-15 23:14:59
From: "Matthew R. Ochs" <redacted>
As staging for the removal of the AFU command pool, remove the reliance
upon the pool for the internal AFU sync command. Instead of obtaining an
AFU command from the pool, dynamically allocate memory with the appropriate
alignment requirements. Since the AFU sync service is only executed from
the process environment, blocking is acceptable.
Signed-off-by: Matthew R. Ochs <redacted>
---
drivers/scsi/cxlflash/main.c | 25 ++++++++++++-------------
1 file changed, 12 insertions(+), 13 deletions(-)
@@ -1847,8 +1847,8 @@ int cxlflash_afu_sync(struct afu *afu, ctx_hndl_t ctx_hndl_u,structcxlflash_cfg*cfg=afu->parent;structdevice*dev=&cfg->dev->dev;structafu_cmd*cmd=NULL;+char*buf=NULL;intrc=0;-intretry_cnt=0;staticDEFINE_MUTEX(sync_active);if(cfg->state!=STATE_NORMAL){
@@ -1857,23 +1857,23 @@ int cxlflash_afu_sync(struct afu *afu, ctx_hndl_t ctx_hndl_u,}mutex_lock(&sync_active);-retry:-cmd=cmd_checkout(afu);-if(unlikely(!cmd)){-retry_cnt++;-udelay(1000*retry_cnt);-if(retry_cnt<MC_RETRY_CNT)-gotoretry;-dev_err(dev,"%s: could not get a free command\n",__func__);+buf=kzalloc(sizeof(*cmd)+__alignof__(*cmd)-1,GFP_KERNEL);+if(unlikely(!buf)){+dev_err(dev,"%s: no memory for command\n",__func__);rc=-1;gotoout;}-pr_debug("%s: afu=%p cmd=%p %d\n",__func__,afu,cmd,ctx_hndl_u);+cmd=(structafu_cmd*)PTR_ALIGN(buf,__alignof__(*cmd));+init_completion(&cmd->cevent);+spin_lock_init(&cmd->slock);+cmd->parent=afu;-memset(cmd->rcb.cdb,0,sizeof(cmd->rcb.cdb));+pr_debug("%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;+cmd->rcb.msi=SISL_MSI_RRQ_UPDATED;cmd->rcb.port_sel=0x0;/* NA */cmd->rcb.lun_id=0x0;/* NA */cmd->rcb.data_len=0x0;
From: Uma Krishnan <hidden> Date: 2016-11-15 23:15:08
From: "Matthew R. Ochs" <redacted>
Instead of using a private pool of AFU commands, use cmd_size to prime
the private pool of SCSI commands such that they are allocated with a
size large enough to contain an aligned AFU command. Use scsi_cmd_priv()
to derive the aligned/zeroed private command on queuecommand and TMF
paths. Remove cmd_checkout() as it is no longer required. The remaining
AFU private command infrastructure will be removed in a cleanup commit.
Signed-off-by: Matthew R. Ochs <redacted>
---
drivers/scsi/cxlflash/common.h | 14 +++++++++
drivers/scsi/cxlflash/main.c | 65 +++++++-----------------------------------
2 files changed, 25 insertions(+), 54 deletions(-)
@@ -401,13 +368,6 @@ static int send_tmf(struct afu *afu, struct scsi_cmnd *scp, u64 tmfcmd)intrc=0;ulongto;-cmd=cmd_checkout(afu);-if(unlikely(!cmd)){-dev_err(dev,"%s: could not get a free command\n",__func__);-rc=SCSI_MLQUEUE_HOST_BUSY;-gotoout;-}-/* When Task Management Function is active do not send another */spin_lock_irqsave(&cfg->tmf_slock,lock_flags);if(cfg->tmf_active)
@@ -427,8 +388,10 @@ static int send_tmf(struct afu *afu, struct scsi_cmnd *scp, u64 tmfcmd)cmd->rcb.req_flags=(SISL_REQ_FLAGS_PORT_LUN_ID|SISL_REQ_FLAGS_SUP_UNDERRUN|lflag);-/* Stash the scp in the reserved field, for reuse during interrupt */+/* Stash the scp in the command, for reuse during interrupt */cmd->rcb.scp=scp;+cmd->parent=afu;+spin_lock_init(&cmd->slock);/* Copy the CDB from the cmd passed in */memcpy(cmd->rcb.cdb,&tmfcmd,sizeof(tmfcmd));
@@ -436,7 +399,6 @@ static int send_tmf(struct afu *afu, struct scsi_cmnd *scp, u64 tmfcmd)/* Send the command */rc=send_cmd(afu,cmd);if(unlikely(rc)){-cmd_checkin(cmd);spin_lock_irqsave(&cfg->tmf_slock,lock_flags);cfg->tmf_active=false;spin_unlock_irqrestore(&cfg->tmf_slock,lock_flags);
@@ -537,17 +499,11 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp)break;}-cmd=cmd_checkout(afu);-if(unlikely(!cmd)){-dev_err(dev,"%s: could not get a free command\n",__func__);-rc=SCSI_MLQUEUE_HOST_BUSY;-gotoout;-}-kref_get(&cfg->afu->mapcount);kref_got=1;cmd->rcb.ctx_id=afu->ctx_hndl;+cmd->rcb.msi=SISL_MSI_RRQ_UPDATED;cmd->rcb.port_sel=port_sel;cmd->rcb.lun_id=lun_to_lunid(scp->device->lun);
@@ -561,6 +517,8 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp)/* Stash the scp in the reserved field, for reuse during interrupt */cmd->rcb.scp=scp;+cmd->parent=afu;+spin_lock_init(&cmd->slock);nseg=scsi_dma_map(scp);if(unlikely(nseg<0)){
@@ -581,10 +539,8 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp)/* Send the command */rc=send_cmd(afu,cmd);-if(unlikely(rc)){-cmd_checkin(cmd);+if(unlikely(rc))scsi_dma_unmap(scp);-}out:if(kref_got)
@@ -2338,6 +2294,7 @@ static struct scsi_host_template driver_template = {.change_queue_depth=cxlflash_change_queue_depth,.cmd_per_lun=CXLFLASH_MAX_CMDS_PER_LUN,.can_queue=CXLFLASH_MAX_CMDS,+.cmd_size=sizeof(structafu_cmd)+__alignof__(structafu_cmd)-1,.this_id=-1,.sg_tablesize=1,/* No scatter gather support */.max_sectors=CXLFLASH_MAX_SECTORS,
From: Uma Krishnan <hidden> Date: 2016-11-15 23:15:26
From: "Matthew R. Ochs" <redacted>
Clean up and remove the remaining private command pool infrastructure
that is no longer required.
Signed-off-by: Matthew R. Ochs <redacted>
---
drivers/scsi/cxlflash/common.h | 7 -----
drivers/scsi/cxlflash/main.c | 68 ------------------------------------------
2 files changed, 75 deletions(-)
@@ -164,10 +162,6 @@ struct afu {/* Stuff requiring alignment go first. */u64rrq_entry[NUM_RRQ_ENTRY];/* 2K RRQ */-/*-*Command&dataforAFUcommands.-*/-structafu_cmdcmd[CXLFLASH_NUM_CMDS];/* Beware of alignment till here. Preferably introduce new*fieldsafterthispoint
@@ -189,7 +183,6 @@ struct afu {boolread_room;atomic64_troom;u64hb;-u32cmd_couts;/* Number of command checkouts */u32internal_lun;/* User-desired LUN mode for this AFU */charversion[16];
@@ -35,33 +35,6 @@ MODULE_AUTHOR("Matthew R. Ochs <mrochs@linux.vnet.ibm.com>");MODULE_LICENSE("GPL");/**-*cmd_checkin()-checksinanAFUcommand-*@cmd:AFUcommandtocheckin.-*-*Safetopasscommandsthathavealreadybeencheckedin.Several-*internaltrackingfieldsareresetaspartofthecheckin.Note-*thattheseareintentionallyresetpriortotogglingthefreebit-*toavoidclobberingvaluesintheeventthatthecommandischecked-*outrightaway.-*/-staticvoidcmd_checkin(structafu_cmd*cmd)-{-cmd->rcb.scp=NULL;-cmd->rcb.timeout=0;-cmd->sa.ioasc=0;-cmd->cmd_tmf=false;-cmd->sa.host_use[0]=0;/* clears both completion and retry bytes */--if(unlikely(atomic_inc_return(&cmd->free)!=1)){-pr_err("%s: Freeing cmd (%d) that is not in use!\n",-__func__,cmd->slot);-return;-}--pr_devel("%s: released cmd %p index=%d\n",__func__,cmd,cmd->slot);-}--/***process_cmd_err()-commanderrorhandler*@cmd:AFUcommandthatexperiencedtheerror.*@scp:SCSIcommandassociatedwiththeAFUcommandinerror.
@@ -819,7 +776,6 @@ static void cxlflash_remove(struct pci_dev *pdev)staticintalloc_mem(structcxlflash_cfg*cfg){intrc=0;-inti;structdevice*dev=&cfg->dev->dev;/* AFU is ~12k, i.e. only one 64k page or up to four 4k pages */
@@ -833,12 +789,6 @@ static int alloc_mem(struct cxlflash_cfg *cfg)}cfg->afu->parent=cfg;cfg->afu->afu_map=NULL;--for(i=0;i<CXLFLASH_NUM_CMDS;i++){-atomic_set(&cfg->afu->cmd[i].free,1);-cfg->afu->cmd[i].slot=i;-}-out:returnrc;}
@@ -1468,13 +1418,6 @@ static void init_pcr(struct cxlflash_cfg *cfg)/* Program the Endian Control for the master context */writeq_be(SISL_ENDIAN_CTRL,&afu->host_map->endian_ctrl);--/* Initialize cmd fields that never change */-for(i=0;i<CXLFLASH_NUM_CMDS;i++){-afu->cmd[i].rcb.ctx_id=afu->ctx_hndl;-afu->cmd[i].rcb.msi=SISL_MSI_RRQ_UPDATED;-afu->cmd[i].rcb.rrq=0x0;-}}/**
@@ -1563,19 +1506,8 @@ static int init_global(struct cxlflash_cfg *cfg)staticintstart_afu(structcxlflash_cfg*cfg){structafu*afu=cfg->afu;-structafu_cmd*cmd;--inti=0;intrc=0;-for(i=0;i<CXLFLASH_NUM_CMDS;i++){-cmd=&afu->cmd[i];--init_completion(&cmd->cevent);-spin_lock_init(&cmd->slock);-cmd->parent=afu;-}-init_pcr(cfg);/* After an AFU reset, RRQ entries are stale, clear them */
From: Uma Krishnan <hidden> Date: 2016-11-15 23:15:30
From: "Matthew R. Ochs" <redacted>
With the removal of the static private command pool, the ability to
'complete' outstanding commands was lost. While not an issue for the
commands originating outside the driver, internal AFU commands are
synchronous and therefore have a timeout associated with them. To
avoid a stale memory access, the tear down sequence needs to ensure
that there are not any active commands before proceeding. As these
internal AFU commands are rare events, the simplest way to accomplish
this is detecting the activity and waiting for it to timeout.
Signed-off-by: Matthew R. Ochs <redacted>
---
drivers/scsi/cxlflash/common.h | 1 +
drivers/scsi/cxlflash/main.c | 6 +++++-
2 files changed, 6 insertions(+), 1 deletion(-)
@@ -181,6 +181,7 @@ struct afu {u64*hrrq_curr;booltoggle;boolread_room;+atomic_tcmds_active;/* Number of currently active AFU commands */atomic64_troom;u64hb;u32internal_lun;/* User-desired LUN mode for this AFU */
@@ -1745,6 +1747,7 @@ int cxlflash_afu_sync(struct afu *afu, ctx_hndl_t ctx_hndl_u,}mutex_lock(&sync_active);+atomic_inc(&afu->cmds_active);buf=kzalloc(sizeof(*cmd)+__alignof__(*cmd)-1,GFP_KERNEL);if(unlikely(!buf)){dev_err(dev,"%s: no memory for command\n",__func__);
From: Uma Krishnan <hidden> Date: 2016-11-15 23:15:39
From: "Matthew R. Ochs" <redacted>
The original design of the cxlflash driver required AFU commands
to convey state information across multiple threads. The IOASA
"host use" byte was used to track if a command was done, errored,
or timed out. A per-command spin lock was used to serialize access
to this byte. As this is no longer required with the introduction
of completions and various refactoring over time, the spin lock,
state tracking, and associated code can be removed. To support the
simplification, the wait_resp() routine is refactored to return a
success or failure. Additionally, as the simplification to the
AFU internal command routine, explicit assignments of AFU command
fields to zero are removed as the memory is zeroed upon allocation.
Signed-off-by: Matthew R. Ochs <redacted>
---
drivers/scsi/cxlflash/common.h | 8 +-------
drivers/scsi/cxlflash/main.c | 46 ++++++++++++++----------------------------
2 files changed, 16 insertions(+), 38 deletions(-)
@@ -63,11 +63,6 @@ static inline void check_sizes(void)/* AFU defines a fixed size of 4K for command buffers (borrow 4K page define) */#define CMD_BUFSIZE SIZE_4K-/* flags in IOA status area for host use */-#define B_DONE 0x01-#define B_ERROR 0x02 /* set with B_DONE */-#define B_TIMEOUT 0x04 /* set with B_DONE & B_ERROR */-enumcxlflash_lr_state{LINK_RESET_INVALID,LINK_RESET_REQUIRED,
@@ -133,9 +128,8 @@ struct cxlflash_cfg {structafu_cmd{structsisl_ioarcbrcb;/* IOARCB (cache line aligned) */structsisl_ioasasa;/* IOASA must follow IOARCB */-spinlock_tslock;-structcompletioncevent;structafu*parent;+structcompletioncevent;u8cmd_tmf:1;
@@ -364,7 +358,6 @@ static int send_tmf(struct afu *afu, struct scsi_cmnd *scp, u64 tmfcmd)/* Stash the scp in the command, for reuse during interrupt */cmd->rcb.scp=scp;cmd->parent=afu;-spin_lock_init(&cmd->slock);/* Copy the CDB from the cmd passed in */memcpy(cmd->rcb.cdb,&tmfcmd,sizeof(tmfcmd));
@@ -491,7 +484,6 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp)/* Stash the scp in the reserved field, for reuse during interrupt */cmd->rcb.scp=scp;cmd->parent=afu;-spin_lock_init(&cmd->slock);nseg=scsi_dma_map(scp);if(unlikely(nseg<0)){
@@ -1765,10 +1756,6 @@ int cxlflash_afu_sync(struct afu *afu, ctx_hndl_t ctx_hndl_u,cmd->rcb.req_flags=SISL_REQ_FLAGS_AFU_CMD;cmd->rcb.ctx_id=afu->ctx_hndl;cmd->rcb.msi=SISL_MSI_RRQ_UPDATED;-cmd->rcb.port_sel=0x0;/* NA */-cmd->rcb.lun_id=0x0;/* NA */-cmd->rcb.data_len=0x0;-cmd->rcb.data_ea=0x0;cmd->rcb.timeout=MC_AFU_SYNC_TIMEOUT;cmd->rcb.cdb[0]=0xC0;/* AFU Sync */
@@ -1782,11 +1769,8 @@ int cxlflash_afu_sync(struct afu *afu, ctx_hndl_t ctx_hndl_u,if(unlikely(rc))gotoout;-wait_resp(afu,cmd);--/* Set on timeout */-if(unlikely((cmd->sa.ioasc!=0)||-(cmd->sa.host_use_b[0]&B_ERROR)))+rc=wait_resp(afu,cmd);+if(unlikely(rc))rc=-1;out:atomic_dec(&afu->cmds_active);
From: Uma Krishnan <hidden> Date: 2016-11-15 23:15:52
From: "Matthew R. Ochs" <redacted>
The send_tmf() routine includes some copy/paste cruft that can be
removed as well as the setting of an AFU command-specific while
holding the tmf_slock. While not a bug, it is out of place and
should be shifted down alongside the other command initialization
statements for clarity.
Signed-off-by: Matthew R. Ochs <redacted>
---
drivers/scsi/cxlflash/main.c | 22 +++++++---------------
1 file changed, 7 insertions(+), 15 deletions(-)
@@ -342,27 +340,21 @@ static int send_tmf(struct afu *afu, struct scsi_cmnd *scp, u64 tmfcmd)!cfg->tmf_active,cfg->tmf_slock);cfg->tmf_active=true;-cmd->cmd_tmf=true;spin_unlock_irqrestore(&cfg->tmf_slock,lock_flags);+cmd->rcb.scp=scp;+cmd->parent=afu;+cmd->cmd_tmf=true;+cmd->rcb.ctx_id=afu->ctx_hndl;cmd->rcb.msi=SISL_MSI_RRQ_UPDATED;cmd->rcb.port_sel=port_sel;cmd->rcb.lun_id=lun_to_lunid(scp->device->lun);--lflag=SISL_REQ_FLAGS_TMF_CMD;-cmd->rcb.req_flags=(SISL_REQ_FLAGS_PORT_LUN_ID|-SISL_REQ_FLAGS_SUP_UNDERRUN|lflag);--/* Stash the scp in the command, for reuse during interrupt */-cmd->rcb.scp=scp;-cmd->parent=afu;--/* Copy the CDB from the cmd passed in */+SISL_REQ_FLAGS_SUP_UNDERRUN|+SISL_REQ_FLAGS_TMF_CMD);memcpy(cmd->rcb.cdb,&tmfcmd,sizeof(tmfcmd));-/* Send the command */rc=send_cmd(afu,cmd);if(unlikely(rc)){spin_lock_irqsave(&cfg->tmf_slock,lock_flags);
From: Uma Krishnan <hidden> Date: 2016-11-15 23:16:05
From: "Matthew R. Ochs" <redacted>
The queuecommand routine is disorganized where it populates the
private command and also contains some logic/statements that are
not needed given that cxlflash devices do not (and likely never
will) support scatter-gather.
Restructure the code to remove the unnecessary logic and create an
organized flow:
handle state -> DMA map -> populate command -> send command
Signed-off-by: Matthew R. Ochs <redacted>
---
drivers/scsi/cxlflash/main.c | 50 ++++++++++++++++++--------------------------
1 file changed, 20 insertions(+), 30 deletions(-)
@@ -460,45 +460,35 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp)kref_get(&cfg->afu->mapcount);kref_got=1;-cmd->rcb.ctx_id=afu->ctx_hndl;-cmd->rcb.msi=SISL_MSI_RRQ_UPDATED;-cmd->rcb.port_sel=port_sel;-cmd->rcb.lun_id=lun_to_lunid(scp->device->lun);--if(scp->sc_data_direction==DMA_TO_DEVICE)-lflag=SISL_REQ_FLAGS_HOST_WRITE;-else-lflag=SISL_REQ_FLAGS_HOST_READ;+if(likely(sg)){+nseg=scsi_dma_map(scp);+if(unlikely(nseg<0)){+dev_err(dev,"%s: Fail DMA map!\n",__func__);+rc=SCSI_MLQUEUE_HOST_BUSY;+gotoout;+}-cmd->rcb.req_flags=(SISL_REQ_FLAGS_PORT_LUN_ID|-SISL_REQ_FLAGS_SUP_UNDERRUN|lflag);+cmd->rcb.data_len=sg_dma_len(sg);+cmd->rcb.data_ea=sg_dma_address(sg);+}-/* Stash the scp in the reserved field, for reuse during interrupt */cmd->rcb.scp=scp;cmd->parent=afu;-nseg=scsi_dma_map(scp);-if(unlikely(nseg<0)){-dev_err(dev,"%s: Fail DMA map! nseg=%d\n",-__func__,nseg);-rc=SCSI_MLQUEUE_HOST_BUSY;-gotoout;-}+cmd->rcb.ctx_id=afu->ctx_hndl;+cmd->rcb.msi=SISL_MSI_RRQ_UPDATED;+cmd->rcb.port_sel=port_sel;+cmd->rcb.lun_id=lun_to_lunid(scp->device->lun);-ncount=scsi_sg_count(scp);-scsi_for_each_sg(scp,sg,ncount,i){-cmd->rcb.data_len=sg_dma_len(sg);-cmd->rcb.data_ea=sg_dma_address(sg);-}+if(scp->sc_data_direction==DMA_TO_DEVICE)+req_flags|=SISL_REQ_FLAGS_HOST_WRITE;-/* Copy the CDB from the scsi_cmnd passed in */+cmd->rcb.req_flags=req_flags;memcpy(cmd->rcb.cdb,scp->cmnd,sizeof(cmd->rcb.cdb));-/* Send the command */rc=send_cmd(afu,cmd);if(unlikely(rc))scsi_dma_unmap(scp);-out:if(kref_got)kref_put(&afu->mapcount,afu_unmap);
From: Uma Krishnan <hidden> Date: 2016-11-15 23:16:14
From: "Matthew R. Ochs" <redacted>
As staging for supporting hardware with a different queuing mechanism,
move the send_cmd() and context_reset() routines to function pointers
that are configured when the AFU is initialized. In addition, rename
the existing routines to better reflect the queue model they support.
Signed-off-by: Matthew R. Ochs <redacted>
---
drivers/scsi/cxlflash/common.h | 3 +++
drivers/scsi/cxlflash/main.c | 21 +++++++++++----------
2 files changed, 14 insertions(+), 10 deletions(-)
@@ -1656,6 +1654,9 @@ static int init_afu(struct cxlflash_cfg *cfg)gotoerr2;}+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);
@@ -1747,7 +1748,7 @@ int cxlflash_afu_sync(struct afu *afu, ctx_hndl_t ctx_hndl_u,*((__be16*)&cmd->rcb.cdb[2])=cpu_to_be16(ctx_hndl_u);*((__be32*)&cmd->rcb.cdb[4])=cpu_to_be32(res_hndl_u);-rc=send_cmd(afu,cmd);+rc=afu->send_cmd(afu,cmd);if(unlikely(rc))gotoout;
From: Uma Krishnan <hidden> Date: 2016-11-15 23:16:24
From: "Matthew R. Ochs" <redacted>
Currently, when sending a SCSI command, the pointer is stored in a
reserved field of the AFU command descriptor for retrieval once the
SCSI command has completed. In order to support new descriptor formats
that make use of the reserved field, the pointer is migrated to outside
the descriptor where it can still be found during completion processing.
Signed-off-by: Matthew R. Ochs <redacted>
---
drivers/scsi/cxlflash/common.h | 1 +
drivers/scsi/cxlflash/main.c | 10 +++++-----
drivers/scsi/cxlflash/sislite.h | 2 +-
3 files changed, 7 insertions(+), 6 deletions(-)
@@ -72,7 +72,7 @@ struct sisl_ioarcb {u16timeout;/* in units specified by req_flags */u32rsvd1;u8cdb[16];/* must be in big endian */-structscsi_cmnd*scp;+u64reserved;/* Reserved area */}__packed;structsisl_rc{
From: Matthew R. Ochs <hidden> Date: 2016-11-17 19:20:20
On Nov 15, 2016, at 5:13 PM, Uma Krishnan [off-list ref] =
wrote:
=20
The following Oops is encountered when blk_mq is enabled with the
cxlflash driver:
=20
[ 2960.817172] Oops: Kernel access of bad area, sig: 11 [#5]
[ 2960.817309] NIP __blk_mq_run_hw_queue+0x278/0x4c0
[ 2960.817313] LR __blk_mq_run_hw_queue+0x2bc/0x4c0
[ 2960.817314] Call Trace:
[ 2960.817320] __blk_mq_run_hw_queue+0x2bc/0x4c0 (unreliable)
[ 2960.817324] blk_mq_run_hw_queue+0xd8/0x100
[ 2960.817329] blk_mq_insert_requests+0x14c/0x1f0
[ 2960.817333] blk_mq_flush_plug_list+0x150/0x190
[ 2960.817338] blk_flush_plug_list+0x11c/0x2b0
[ 2960.817344] blk_finish_plug+0x58/0x80
[ 2960.817348] __do_page_cache_readahead+0x1c0/0x2e0
[ 2960.817352] force_page_cache_readahead+0x68/0xd0
[ 2960.817356] generic_file_read_iter+0x43c/0x6a0
[ 2960.817359] blkdev_read_iter+0x68/0xa0
[ 2960.817361] __vfs_read+0x11c/0x180
[ 2960.817364] vfs_read+0xa4/0x1c0
[ 2960.817366] SyS_read+0x6c/0x110
[ 2960.817369] system_call+0x38/0xb4
=20
The SCSI blk_mq stack assumes that sg_tablesize is always a non-zero
value with scsi_mq_setup_tags() allocating tags using sg_tablesize.
The cxlflash driver currently uses SG_NONE (0) for the sg_tablesize
as the devices it supports are not capable of scatter gather. This
mismatch of values results in the Oops above.
=20
To resolve this issue, sg_tablesize for cxlflash can simply be set
to 1, a value which satisfies the constraints in cxlflash and the
lack of support of SG_NONE in SCSI blk_mq.
=20
Signed-off-by: Uma Krishnan <redacted>
From: Matthew R. Ochs <hidden> Date: 2016-11-17 19:20:49
On Nov 15, 2016, at 5:14 PM, Uma Krishnan [off-list ref] =
wrote:
=20
During test, the following crash was observed:
=20
[34538.981505] Faulting instruction address: 0xd000000007c9c870
cpu 0x9: Vector: 300 (Data Access) at [c0000007f1e8f590]
pc: d000000007c9c870: cxlflash_restore_luntable+0x70/0x1d0 =
[c0000007f1e8fc30] c000000000041db8 eeh_handle_event+0x178/0x330
[c0000007f1e8fce0] c000000000042118 eeh_event_handler+0x1a8/0x1b0
[c0000007f1e8fd80] c00000000011420c kthread+0xec/0x100
[c0000007f1e8fe30] c00000000000a47c ret_from_kernel_thread+0x5c/0xe0
=20
When superpipe mode is disabled for a LUN, the references for the
local lun are deleted but the LUN is still identified as being present
in the LUN table. This mismatched state can result in the above crash
when the LUN table is restored during an error recovery operation.
=20
To fix this issue, the local LUN information structure is updated to
reflect the LUN is no longer in the LUN table once all references to
the LUN are gone.
=20
Signed-off-by: Uma Krishnan <redacted>
From: Matthew R. Ochs <hidden> Date: 2016-11-17 19:21:15
On Nov 15, 2016, at 5:14 PM, Uma Krishnan [off-list ref] =
wrote:
=20
Currently, the context reset routine waits for command room to
be available before sending the reset request. Per review of the
SISLite specification and clarifications from the CXL Flash AFU
designers, this wait is unnecessary. The reset request can be
sent anytime regardless of command room, so long as only a single
reset request is active at any one point in time.
=20
This commit simplifies the reset routine by removing the wait for
command room. Additionally it adds a debug trace to help pinpoint
hardware errors when a context reset does not complete.
=20
Signed-off-by: Uma Krishnan <redacted>
From: Matthew R. Ochs <hidden> Date: 2016-11-17 19:36:50
Hi Uma,
I do see a potential hang issue with this patch. See my comments below.
-matt
=20
On Nov 15, 2016, at 5:14 PM, Uma Krishnan [off-list ref] =
wrote:
=20
During test, a command room violation interrupt is occasionally seen
for the master context when the CXL flash devices are stressed.
=20
After studying the code, there could be gaps in the way command room
value is being cached in cxlflash. When the cached command room is =
zero
the thread attempting to send becomes burdened with updating the =
cached
value with the actual value from the AFU. Today, this is handled with
an atomic set operation of the raw value read. Following the atomic
update, the thread proceeds to send.
=20
This behavior is incorrect on two counts:
=20
- The update fails to take into account the current thread and its
consumption of one of the hardware commands.
=20
- The update does not take into account other threads also =
atomically
updating. Per design, a worker thread updates the cached value =
when
a send thread times out. By not performing an atomic =
compare/exchange,
the cached value can be incorrectly clobbered.
=20
To correct these issues, the runtime updates of the cached command =
room
are updated to use atomic64_cmpxchg() and the send routine is updated =
to
quoted hunk
take into account the current thread consuming a hardware command.
=20
Signed-off-by: Uma Krishnan <redacted>
---
drivers/scsi/cxlflash/main.c | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
=20
When this path is invoked, the current thread is consuming the last =
entry
available entry before the room must be read again. While the change
below is fine for circumstances where the hardware queue has room for
more than one command, consider a scenario where the queue has room
for only 1 command (the command that you just consumed via the atomic
but are not really consuming with a MMIO due to the revised goto).
In such a scenario this code would loop endlessly, bypassing the timeout
logic completely, until the read room reflected a value greater than 1.
do {
room =3D readq_be(&afu->host_map->cmd_room);
- atomic64_set(&afu->room, room);
- if (room)
- goto write_ioarrin;
+ if (room) {
+ atomic64_cmpxchg(&afu->room, 0, room);
+ goto retry;
+ }
If you instead fully consume the entry (goto write_ioarrin - similar as =
it was
before) and take into account the consumption when you update the cached
value (i.e.: cmpxchg(..., 0, room - 1) the scenario described above will =
not occur.
From: Uma Krishnan <hidden> Date: 2016-11-17 22:30:33
Thanks for catching this Matt. Looking into this. Will send out a V2.
On 11/17/2016 1:36 PM, Matthew R. Ochs wrote:
Hi Uma,
I do see a potential hang issue with this patch. See my comments below.
-matt
quoted
On Nov 15, 2016, at 5:14 PM, Uma Krishnan [off-list ref] wrote:
During test, a command room violation interrupt is occasionally seen
for the master context when the CXL flash devices are stressed.
After studying the code, there could be gaps in the way command room
value is being cached in cxlflash. When the cached command room is zero
the thread attempting to send becomes burdened with updating the cached
value with the actual value from the AFU. Today, this is handled with
an atomic set operation of the raw value read. Following the atomic
update, the thread proceeds to send.
This behavior is incorrect on two counts:
- The update fails to take into account the current thread and its
consumption of one of the hardware commands.
- The update does not take into account other threads also atomically
updating. Per design, a worker thread updates the cached value when
a send thread times out. By not performing an atomic compare/exchange,
the cached value can be incorrectly clobbered.
To correct these issues, the runtime updates of the cached command room
are updated to use atomic64_cmpxchg() and the send routine is updated to
take into account the current thread consuming a hardware command.
Signed-off-by: Uma Krishnan <redacted>
---
drivers/scsi/cxlflash/main.c | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
When this path is invoked, the current thread is consuming the last entry
available entry before the room must be read again. While the change
below is fine for circumstances where the hardware queue has room for
more than one command, consider a scenario where the queue has room
for only 1 command (the command that you just consumed via the atomic
but are not really consuming with a MMIO due to the revised goto).
In such a scenario this code would loop endlessly, bypassing the timeout
logic completely, until the read room reflected a value greater than 1.
quoted
do {
room = readq_be(&afu->host_map->cmd_room);
- atomic64_set(&afu->room, room);
- if (room)
- goto write_ioarrin;
+ if (room) {
+ atomic64_cmpxchg(&afu->room, 0, room);
+ goto retry;
+ }
If you instead fully consume the entry (goto write_ioarrin - similar as it was
before) and take into account the consumption when you update the cached
value (i.e.: cmpxchg(..., 0, room - 1) the scenario described above will not occur.