From: Matthew R. Ochs <hidden> Date: 2015-09-25 23:10:56
This patch set contains various fixes and corrections for issues that
were found during test and code review. The series is based upon the
code upstreamed in 4.3 and is intended for the rc phase. The entire
set is bisectable. Please reference the changelog below for details
on what has been altered from previous versions of this patch set.
v4 Changes:
- Incorporate comments from Brian King
- Removed unnecessary check_state() parameter from "Fix to avoid CXL..."
- Added patch to fix potential deadlock on EEH
- Removed patch to avoid state change collision
- Changed fops initialization location in "Fix to avoid corrupting..."
v3 Changes:
- Rebased the series on top of patch by Dan Carpenter ("a couple off...")
- Incorporate comments from David Laight
- Incorporate comments from Tomas Henzl
- Incorporate comments from Brian King
- Removed patch to stop interrupt processing on remove
- Removed double scsi_device_put() from "Fix potential oops"
- Fixed usage of scnprintf() in "Refine host/device attributes"
- Removed unnecessary parenthesis from "Fix read capacity timeout"
- Added patch to use correct operator for doubling delay
- Changed location of cancel_work_sync() in "Fix to prevent workq..."
- Removed local mutex from cxlflash_afu_sync() in "Fix to avoid state..."
- Added patch to correctly identify a failed function in a trace
- Added patch to fix a fops corruption bug
v2 Changes:
- Incorporate comments from Ian Munsie
- Rework commit messages to be more descriptive
- Add state change serialization patch
Manoj Kumar (4):
cxlflash: Fix to avoid invalid port_sel value
cxlflash: Replace magic numbers with literals
cxlflash: Fix read capacity timeout
cxlflash: Fix to double the delay each time
Matthew R. Ochs (28):
cxlflash: Fix potential oops following LUN removal
cxlflash: Fix data corruption when vLUN used over multiple cards
cxlflash: Fix to avoid sizeof(bool)
cxlflash: Fix context encode mask width
cxlflash: Fix to avoid CXL services during EEH
cxlflash: Correct naming of limbo state and waitq
cxlflash: Make functions static
cxlflash: Refine host/device attributes
cxlflash: Fix to avoid spamming the kernel log
cxlflash: Fix to avoid stall while waiting on TMF
cxlflash: Fix location of setting resid
cxlflash: Fix host link up event handling
cxlflash: Fix async interrupt bypass logic
cxlflash: Remove dual port online dependency
cxlflash: Fix AFU version access/storage and add check
cxlflash: Correct usage of scsi_host_put()
cxlflash: Fix to prevent workq from accessing freed memory
cxlflash: Correct behavior in device reset handler following EEH
cxlflash: Remove unnecessary scsi_block_requests
cxlflash: Fix function prolog parameters and return codes
cxlflash: Fix MMIO and endianness errors
cxlflash: Fix to prevent EEH recovery failure
cxlflash: Correct spelling, grammar, and alignment mistakes
cxlflash: Fix to prevent stale AFU RRQ
MAINTAINERS: Add cxlflash driver
cxlflash: Fix to avoid corrupting adapter fops
cxlflash: Correct trace string
cxlflash: Fix to avoid potential deadlock on EEH
MAINTAINERS | 9 +
drivers/scsi/cxlflash/common.h | 30 +-
drivers/scsi/cxlflash/lunmgt.c | 9 +-
drivers/scsi/cxlflash/main.c | 1529 ++++++++++++++++++++-----------------
drivers/scsi/cxlflash/main.h | 1 +
drivers/scsi/cxlflash/sislite.h | 8 +-
drivers/scsi/cxlflash/superpipe.c | 204 +++--
drivers/scsi/cxlflash/superpipe.h | 13 +-
drivers/scsi/cxlflash/vlun.c | 68 +-
9 files changed, 1043 insertions(+), 828 deletions(-)
--
2.1.0
From: Matthew R. Ochs <hidden> Date: 2015-09-25 23:12:59
From: Manoj Kumar <redacted>
If two concurrent MANAGE_LUN ioctls are issued with the same
WWID parameter, it would result in an incorrect value of port_sel.
This is because port_sel is modified without any locks being
held. If the first caller stalls after the return from
find_and_create_lun(), the value of port_sel will be set
incorrectly to indicate a single port, though in this case
it should have been set to both ports.
To fix, use the global mutex to serialize the lookup of the
WWID and the subsequent modification of port_sel.
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
Reviewed-by: Brian King <redacted>
---
drivers/scsi/cxlflash/lunmgt.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
From: Matthew R. Ochs <hidden> Date: 2015-09-25 23:14:01
From: Manoj Kumar <redacted>
Magic numbers are not meaningful and can create confusion. As a
remedy, replace them with descriptive literals.
Replace 512 with literal MAX_SECTOR_UNIT.
Replace 5 with literal CMD_RETRIES.
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
Reviewed-by: Brian King <redacted>
---
drivers/scsi/cxlflash/superpipe.c | 6 ++++--
drivers/scsi/cxlflash/superpipe.h | 3 +++
drivers/scsi/cxlflash/vlun.c | 3 ++-
3 files changed, 9 insertions(+), 3 deletions(-)
@@ -315,7 +315,8 @@ retry:retry_cnt?"re":"",scsi_cmd[0]);result=scsi_execute(sdev,scsi_cmd,DMA_FROM_DEVICE,cmd_buf,-CMD_BUFSIZE,sense_buf,tout,5,0,NULL);+CMD_BUFSIZE,sense_buf,tout,CMD_RETRIES,+0,NULL);if(driver_byte(result)==DRIVER_SENSE){result&=~(0xFF<<24);/* DRIVER_SENSE is not an error */
From: Matthew R. Ochs <hidden> Date: 2015-09-25 23:14:35
From: Manoj Kumar <redacted>
The timeout value for read capacity is too small. Certain devices
may take longer to respond and thus the command may prematurely
timeout. Additionally the literal used for the timeout is stale.
Update the timeout to 30 seconds (matches the value used in sd.c)
and rework the timeout literal to a more appropriate description.
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
Reviewed-by: Brian King <redacted>
---
drivers/scsi/cxlflash/superpipe.c | 9 ++++-----
drivers/scsi/cxlflash/superpipe.h | 2 +-
drivers/scsi/cxlflash/vlun.c | 4 ++--
3 files changed, 7 insertions(+), 8 deletions(-)
@@ -315,8 +315,7 @@ retry:retry_cnt?"re":"",scsi_cmd[0]);result=scsi_execute(sdev,scsi_cmd,DMA_FROM_DEVICE,cmd_buf,-CMD_BUFSIZE,sense_buf,tout,CMD_RETRIES,-0,NULL);+CMD_BUFSIZE,sense_buf,to,CMD_RETRIES,0,NULL);if(driver_byte(result)==DRIVER_SENSE){result&=~(0xFF<<24);/* DRIVER_SENSE is not an error */
From: Matthew R. Ochs <hidden> Date: 2015-09-25 23:14:37
If the same virtual LUN is accessed over multiple cards, only accesses
made over the first card will be valid. Accesses made over the second
card will go to the wrong LUN causing data corruption.
This is because the global LUN's mode word was being used to determine
whether the LUN table for that card needs to be programmed. The mode
word would be setup by the first card, causing the LUN table for the
second card to not be programmed.
By unconditionally initializing the LUN table (not depending on the
mode word), the problem is avoided.
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
Reviewed-by: Brian King <redacted>
---
drivers/scsi/cxlflash/vlun.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
@@ -915,16 +915,9 @@ int cxlflash_disk_virtual_open(struct scsi_device *sdev, void *arg)pr_debug("%s: ctxid=%llu ls=0x%llx\n",__func__,ctxid,lun_size);+/* Setup the LUNs block allocator on first call */mutex_lock(&gli->mutex);if(gli->mode==MODE_NONE){-/* Setup the LUN table and block allocator on first call */-rc=init_luntable(cfg,lli);-if(rc){-dev_err(dev,"%s: call to init_luntable failed "-"rc=%d!\n",__func__,rc);-gotoerr0;-}-rc=init_vlun(lli);if(rc){dev_err(dev,"%s: call to init_vlun failed rc=%d!\n",
@@ -942,6 +935,13 @@ int cxlflash_disk_virtual_open(struct scsi_device *sdev, void *arg)}mutex_unlock(&gli->mutex);+rc=init_luntable(cfg,lli);+if(rc){+dev_err(dev,"%s: call to init_luntable failed rc=%d!\n",+__func__,rc);+gotoerr1;+}+ctxi=get_context(cfg,rctxid,lli,0);if(unlikely(!ctxi)){dev_err(dev,"%s: Bad context! (%llu)\n",__func__,ctxid);
From: Matthew R. Ochs <hidden> Date: 2015-09-25 23:14:48
Using sizeof(bool) is considered poor form for various reasons and
sparse warns us of that. Correct by changing type from bool to u8.
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
Reviewed-by: Brian King <redacted>
---
drivers/scsi/cxlflash/superpipe.c | 2 +-
drivers/scsi/cxlflash/superpipe.h | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
@@ -97,7 +97,7 @@ struct ctx_info {u32rht_out;/* Number of checked out RHT entries */u32rht_perms;/* User-defined permissions for RHT entries */structllun_info**rht_lun;/* Mapping of RHT entries to LUNs */-bool*rht_needs_ws;/* User-desired write-same function per RHTE */+u8*rht_needs_ws;/* User-desired write-same function per RHTE */structcxl_ioctl_start_workwork;u64ctxid;
From: Matthew R. Ochs <hidden> Date: 2015-09-25 23:14:48
The context encode mask covers more than 32-bits, making it
a long integer. This should be noted by appending the ULL
width suffix to the mask.
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
Reviewed-by: Brian King <redacted>
---
drivers/scsi/cxlflash/superpipe.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
From: Matthew R. Ochs <hidden> Date: 2015-09-25 23:14:55
During an EEH freeze event, certain CXL services should not be
called until after the hardware reset has taken place. Doing so
can result in unnecessary failures and possibly cause other ill
effects by triggering hardware accesses. This translates to a
requirement to quiesce all threads that may potentially use CXL
runtime service during this window. In particular, multiple ioctls
make use of the CXL services when acting on contexts on behalf of
the user. Thus, it is essential to 'drain' running ioctls _before_
proceeding with handling the EEH freeze event.
Create the ability to drain ioctls by wrapping the ioctl handler
call in a read semaphore and then implementing a small routine that
obtains the write semaphore, effectively creating a wait point for
all currently executing ioctls.
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
---
drivers/scsi/cxlflash/common.h | 2 +
drivers/scsi/cxlflash/main.c | 18 +++++--
drivers/scsi/cxlflash/superpipe.c | 98 ++++++++++++++++++++++++---------------
3 files changed, 77 insertions(+), 41 deletions(-)
@@ -2383,16 +2397,14 @@ static pci_ers_result_t cxlflash_pci_error_detected(struct pci_dev *pdev,switch(state){casepci_channel_io_frozen:cfg->state=STATE_LIMBO;--/* Turn off legacy I/O */scsi_block_requests(cfg->host);+drain_ioctls(cfg);rc=cxlflash_mark_contexts_error(cfg);if(unlikely(rc))dev_err(dev,"%s: Failed to mark user contexts!(%d)\n",__func__,rc);term_mc(cfg,UNDO_START);stop_afu(cfg);-returnPCI_ERS_RESULT_NEED_RESET;casepci_channel_io_perm_failure:cfg->state=STATE_FAILTERM;
@@ -1523,41 +1563,6 @@ err1:}/**-*check_state()-checksandrespondstothecurrentadapterstate-*@cfg:Internalstructureassociatedwiththehost.-*-*Thisroutinecanblockandshouldonlybeusedonprocesscontext.-*Notethatwhenwakingupfromwaitinginlimbo,thestateisunknown-*andmustbecheckedagainbeforeproceeding.-*-*Return:0onsuccess,-errnoonfailure-*/-staticintcheck_state(structcxlflash_cfg*cfg)-{-structdevice*dev=&cfg->dev->dev;-intrc=0;--retry:-switch(cfg->state){-caseSTATE_LIMBO:-dev_dbg(dev,"%s: Limbo, going to wait...\n",__func__);-rc=wait_event_interruptible(cfg->limbo_waitq,-cfg->state!=STATE_LIMBO);-if(unlikely(rc))-break;-gotoretry;-caseSTATE_FAILTERM:-dev_dbg(dev,"%s: Failed/Terminating!\n",__func__);-rc=-ENODEV;-break;-default:-break;-}--returnrc;-}--/***cxlflash_afu_recover()-initiatesAFUrecovery*@sdev:SCSIdeviceassociatedwithLUN.*@recover:Recoverioctldatastructure.
@@ -1646,9 +1651,14 @@ retry_recover:/* Test if in error state */reg=readq_be(&afu->ctrl_map->mbox_r);if(reg==-1){-dev_dbg(dev,"%s: MMIO read fail! Wait for recovery...\n",-__func__);-mutex_unlock(&ctxi->mutex);+dev_dbg(dev,"%s: MMIO fail, wait for recovery.\n",__func__);++/*+*Beforecheckingthestate,putbackthecontextobtainedwith+*get_context()asitisnolongerneededandsleepforashort+*periodoftime(seeprolognotes).+*/+put_context(ctxi);ctxi=NULL;ssleep(1);rc=check_state(cfg);
@@ -2001,6 +2019,9 @@ int cxlflash_ioctl(struct scsi_device *sdev, int cmd, void __user *arg){sizeof(structdk_cxlflash_clone),(sioctl)cxlflash_disk_clone},};+/* Hold read semaphore so we can drain if needed */+down_read(&cfg->ioctl_rwsem);+/* Restrict command set to physical support only for internal LUN */if(afu->internal_lun)switch(cmd){
@@ -2082,6 +2103,7 @@ int cxlflash_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)/* fall through to exit */cxlflash_ioctl_exit:+up_read(&cfg->ioctl_rwsem);if(unlikely(rc&&known_ioctl))dev_err(dev,"%s: ioctl %s (%08X) on dev(%d/%d/%d/%llu) ""returned rc %d\n",__func__,
From: Matthew R. Ochs <hidden> Date: 2015-09-25 23:15:02
Limbo is not an accurate representation of this state and is
also not consistent with the terminology that other drivers
use to represent this concept. Rename the state and and its
associated waitq to 'reset'.
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
Reviewed-by: Brian King <redacted>
---
drivers/scsi/cxlflash/common.h | 4 ++--
drivers/scsi/cxlflash/main.c | 26 +++++++++++++-------------
drivers/scsi/cxlflash/superpipe.c | 14 +++++++-------
3 files changed, 22 insertions(+), 22 deletions(-)
@@ -382,8 +382,8 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp)spin_unlock_irqrestore(&cfg->tmf_waitq.lock,lock_flags);switch(cfg->state){-caseSTATE_LIMBO:-dev_dbg_ratelimited(&cfg->dev->dev,"%s: device in limbo!\n",+caseSTATE_RESET:+dev_dbg_ratelimited(&cfg->dev->dev,"%s: device is in reset!\n",__func__);rc=SCSI_MLQUEUE_HOST_BUSY;gotoout;
@@ -479,8 +479,8 @@ static int cxlflash_eh_device_reset_handler(struct scsi_cmnd *scp)if(unlikely(rcr))rc=FAILED;break;-caseSTATE_LIMBO:-wait_event(cfg->limbo_waitq,cfg->state!=STATE_LIMBO);+caseSTATE_RESET:+wait_event(cfg->reset_waitq,cfg->state!=STATE_RESET);if(cfg->state==STATE_NORMAL)break;/* fall through */
@@ -519,7 +519,7 @@ static int cxlflash_eh_host_reset_handler(struct scsi_cmnd *scp)switch(cfg->state){caseSTATE_NORMAL:-cfg->state=STATE_LIMBO;+cfg->state=STATE_RESET;scsi_block_requests(cfg->host);cxlflash_mark_contexts_error(cfg);rcr=cxlflash_afu_reset(cfg);
@@ -528,11 +528,11 @@ static int cxlflash_eh_host_reset_handler(struct scsi_cmnd *scp)cfg->state=STATE_FAILTERM;}elsecfg->state=STATE_NORMAL;-wake_up_all(&cfg->limbo_waitq);+wake_up_all(&cfg->reset_waitq);scsi_unblock_requests(cfg->host);break;-caseSTATE_LIMBO:-wait_event(cfg->limbo_waitq,cfg->state!=STATE_LIMBO);+caseSTATE_RESET:+wait_event(cfg->reset_waitq,cfg->state!=STATE_RESET);if(cfg->state==STATE_NORMAL)break;/* fall through */
@@ -100,7 +100,7 @@ void cxlflash_stop_term_user_contexts(struct cxlflash_cfg *cfg)dev_dbg(dev,"%s: Wait for user contexts to quiesce...\n",__func__);-wake_up_all(&cfg->limbo_waitq);+wake_up_all(&cfg->reset_waitq);ssleep(1);}}
@@ -1233,11 +1233,11 @@ static int check_state(struct cxlflash_cfg *cfg)retry:switch(cfg->state){-caseSTATE_LIMBO:-dev_dbg(dev,"%s: Limbo state, going to wait...\n",__func__);+caseSTATE_RESET:+dev_dbg(dev,"%s: Reset state, going to wait...\n",__func__);up_read(&cfg->ioctl_rwsem);-rc=wait_event_interruptible(cfg->limbo_waitq,-cfg->state!=STATE_LIMBO);+rc=wait_event_interruptible(cfg->reset_waitq,+cfg->state!=STATE_RESET);down_read(&cfg->ioctl_rwsem);if(unlikely(rc))break;
From: Matthew R. Ochs <hidden> Date: 2015-09-25 23:15:06
When a LUN is removed, the sdev that is associated with the LUN
remains intact until its reference count drops to 0. In order
to prevent an sdev from being removed while a context is still
associated with it, obtain an additional reference per-context
for each LUN attached to the context.
This resolves a potential Oops in the release handler when a
dealing with a LUN that has already been removed.
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
Reviewed-by: Brian King <redacted>
---
drivers/scsi/cxlflash/superpipe.c | 35 +++++++++++++++++++++++------------
1 file changed, 23 insertions(+), 12 deletions(-)
@@ -880,6 +880,9 @@ static int _cxlflash_disk_detach(struct scsi_device *sdev,sys_close(lfd);}+/* Release the sdev reference that bound this LUN to the context */+scsi_device_put(sdev);+out:if(put_ctx)put_context(ctxi);
@@ -1287,11 +1290,17 @@ static int cxlflash_disk_attach(struct scsi_device *sdev,}}+rc=scsi_device_get(sdev);+if(unlikely(rc)){+dev_err(dev,"%s: Unable to get sdev reference!\n",__func__);+gotoout;+}+lun_access=kzalloc(sizeof(*lun_access),GFP_KERNEL);if(unlikely(!lun_access)){dev_err(dev,"%s: Unable to allocate lun_access!\n",__func__);rc=-ENOMEM;-gotoout;+gotoerr0;}lun_access->lli=lli;
@@ -1311,21 +1320,21 @@ static int cxlflash_disk_attach(struct scsi_device *sdev,dev_err(dev,"%s: Could not initialize context %p\n",__func__,ctx);rc=-ENODEV;-gotoerr0;+gotoerr1;}ctxid=cxl_process_element(ctx);if(unlikely((ctxid>=MAX_CONTEXT)||(ctxid<0))){dev_err(dev,"%s: ctxid (%d) invalid!\n",__func__,ctxid);rc=-EPERM;-gotoerr1;+gotoerr2;}file=cxl_get_fd(ctx,&cfg->cxl_fops,&fd);if(unlikely(fd<0)){rc=-ENODEV;dev_err(dev,"%s: Could not get file descriptor\n",__func__);-gotoerr1;+gotoerr2;}/* Translate read/write O_* flags from fcntl.h to AFU permission bits */
@@ -1335,7 +1344,7 @@ static int cxlflash_disk_attach(struct scsi_device *sdev,if(unlikely(!ctxi)){dev_err(dev,"%s: Failed to create context! (%d)\n",__func__,ctxid);-gotoerr2;+gotoerr3;}work=&ctxi->work;
@@ -1346,13 +1355,13 @@ static int cxlflash_disk_attach(struct scsi_device *sdev,if(unlikely(rc)){dev_dbg(dev,"%s: Could not start context rc=%d\n",__func__,rc);-gotoerr3;+gotoerr4;}rc=afu_attach(cfg,ctxi);if(unlikely(rc)){dev_err(dev,"%s: Could not attach AFU rc %d\n",__func__,rc);-gotoerr4;+gotoerr5;}/*
From: Matthew R. Ochs <hidden> Date: 2015-09-25 23:15:07
Found during code inspection, that the following functions are not
being used outside of the file where they are defined. Make them static.
int cxlflash_send_cmd(struct afu *, struct afu_cmd *);
void cxlflash_wait_resp(struct afu *, struct afu_cmd *);
int cxlflash_afu_reset(struct cxlflash_cfg *);
struct afu_cmd *cxlflash_cmd_checkout(struct afu *);
void cxlflash_cmd_checkin(struct afu_cmd *);
void init_pcr(struct cxlflash_cfg *);
int init_global(struct cxlflash_cfg *);
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
Reviewed-by: Brian King <redacted>
---
drivers/scsi/cxlflash/common.h | 5 -
drivers/scsi/cxlflash/main.c | 1018 ++++++++++++++++++++--------------------
2 files changed, 509 insertions(+), 514 deletions(-)
@@ -238,7 +238,7 @@ static void cmd_complete(struct afu_cmd *cmd)resid=cmd->sa.resid;cmd_is_tmf=cmd->cmd_tmf;-cxlflash_cmd_checkin(cmd);/* Don't use cmd after here */+cmd_checkin(cmd);/* Don't use cmd after here */pr_debug("%s: calling scsi_set_resid, scp=%p ""result=%X resid=%d\n",__func__,
@@ -260,6 +260,146 @@ static void cmd_complete(struct afu_cmd *cmd)}/**+*context_reset()-timeouthandlerforAFUcommands+*@cmd:AFUcommandthattimedout.+*+*SendsaresettotheAFU.+*/+staticvoidcontext_reset(structafu_cmd*cmd)+{+intnretry=0;+u64rrin=0x1;+u64room=0;+structafu*afu=cmd->parent;+ulonglock_flags;++pr_debug("%s: cmd=%p\n",__func__,cmd);++spin_lock_irqsave(&cmd->slock,lock_flags);++/* Already completed? */+if(cmd->sa.host_use_b[0]&B_DONE){+spin_unlock_irqrestore(&cmd->slock,lock_flags);+return;+}++cmd->sa.host_use_b[0]|=(B_DONE|B_ERROR|B_TIMEOUT);+spin_unlock_irqrestore(&cmd->slock,lock_flags);++/*+*Wereallywanttosendthisresetatallcosts,sospread+*outwaittimeonsuccessiveretriesforavailableroom.+*/+do{+room=readq_be(&afu->host_map->cmd_room);+atomic64_set(&afu->room,room);+if(room)+gotowrite_rrin;+udelay(nretry);+}while(nretry++<MC_ROOM_RETRY_CNT);++pr_err("%s: no cmd_room to send reset\n",__func__);+return;++write_rrin:+nretry=0;+writeq_be(rrin,&afu->host_map->ioarrin);+do{+rrin=readq_be(&afu->host_map->ioarrin);+if(rrin!=0x1)+break;+/* Double delay each time */+udelay(2^nretry);+}while(nretry++<MC_ROOM_RETRY_CNT);+}++/**+*send_cmd()-sendsanAFUcommand+*@afu:AFUassociatedwiththehost.+*@cmd:AFUcommandtosend.+*+*Return:+*0onsuccessorSCSI_MLQUEUE_HOST_BUSY+*/+staticintsend_cmd(structafu*afu,structafu_cmd*cmd)+{+structcxlflash_cfg*cfg=afu->parent;+structdevice*dev=&cfg->dev->dev;+intnretry=0;+intrc=0;+u64room;+longnewval;++/*+*ThisroutineisusedbycriticaluserssuchanAFUsyncandto+*sendataskmanagementfunction(TMF).Thuswewanttoretrya+*bitbeforereturninganerror.Toavoidtheperformancepenalty+*ofMMIO,wespreadtheupdateof'room'overmultiplecommands.+*/+retry:+newval=atomic64_dec_if_positive(&afu->room);+if(!newval){+do{+room=readq_be(&afu->host_map->cmd_room);+atomic64_set(&afu->room,room);+if(room)+gotowrite_ioarrin;+udelay(nretry);+}while(nretry++<MC_ROOM_RETRY_CNT);++dev_err(dev,"%s: no cmd_room to send 0x%X\n",+__func__,cmd->rcb.cdb[0]);++gotono_room;+}elseif(unlikely(newval<0)){+/* This should be rare. i.e. Only if two threads race and+*decrementbeforetheMMIOreadisdone.Inthiscase+*justbenefitfromtheotherthreadhavingupdated+*afu->room.+*/+if(nretry++<MC_ROOM_RETRY_CNT){+udelay(nretry);+gotoretry;+}++gotono_room;+}++write_ioarrin:+writeq_be((u64)&cmd->rcb,&afu->host_map->ioarrin);+out:+pr_devel("%s: cmd=%p len=%d ea=%p rc=%d\n",__func__,cmd,+cmd->rcb.data_len,(void*)cmd->rcb.data_ea,rc);+returnrc;++no_room:+afu->read_room=true;+schedule_work(&cfg->work_q);+rc=SCSI_MLQUEUE_HOST_BUSY;+gotoout;+}++/**+*wait_resp()-pollsforaresponseortimeouttoasentAFUcommand+*@afu:AFUassociatedwiththehost.+*@cmd:AFUcommandthatwassent.+*/+staticvoidwait_resp(structafu*afu,structafu_cmd*cmd)+{+ulongtimeout=msecs_to_jiffies(cmd->rcb.timeout*2*1000);++timeout=wait_for_completion_timeout(&cmd->cevent,timeout);+if(!timeout)+context_reset(cmd);++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);+}++/***send_tmf()-sendsaTaskManagementFunction(TMF)*@afu:AFUtocheckoutfrom.*@scp:SCSIcommandfromstack.
@@ -280,7 +420,7 @@ static int send_tmf(struct afu *afu, struct scsi_cmnd *scp, u64 tmfcmd)ulonglock_flags;intrc=0;-cmd=cxlflash_cmd_checkout(afu);+cmd=cmd_checkout(afu);if(unlikely(!cmd)){pr_err("%s: could not get a free command\n",__func__);rc=SCSI_MLQUEUE_HOST_BUSY;
@@ -313,9 +453,9 @@ static int send_tmf(struct afu *afu, struct scsi_cmnd *scp, u64 tmfcmd)memcpy(cmd->rcb.cdb,&tmfcmd,sizeof(tmfcmd));/* Send the command */-rc=cxlflash_send_cmd(afu,cmd);+rc=send_cmd(afu,cmd);if(unlikely(rc)){-cxlflash_cmd_checkin(cmd);+cmd_checkin(cmd);spin_lock_irqsave(&cfg->tmf_waitq.lock,lock_flags);cfg->tmf_active=false;spin_unlock_irqrestore(&cfg->tmf_waitq.lock,lock_flags);
@@ -398,7 +538,7 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp)break;}-cmd=cxlflash_cmd_checkout(afu);+cmd=cmd_checkout(afu);if(unlikely(!cmd)){pr_err("%s: could not get a free command\n",__func__);rc=SCSI_MLQUEUE_HOST_BUSY;
@@ -438,9 +578,9 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp)memcpy(cmd->rcb.cdb,scp->cmnd,sizeof(cmd->rcb.cdb));/* Send the command */-rc=cxlflash_send_cmd(afu,cmd);+rc=send_cmd(afu,cmd);if(unlikely(rc)){-cxlflash_cmd_checkin(cmd);+cmd_checkin(cmd);scsi_dma_unmap(scp);}
@@ -449,369 +589,55 @@ out:}/**-*cxlflash_eh_device_reset_handler()-resetasingleLUN-*@scp:SCSIcommandtosend.-*-*Return:-*SUCCESSasdefinedinscsi/scsi.h-*FAILEDasdefinedinscsi/scsi.h+*cxlflash_wait_for_pci_err_recovery()-waitforerrorrecoveryduringprobe+*@cxlflash:Internalstructureassociatedwiththehost.*/-staticintcxlflash_eh_device_reset_handler(structscsi_cmnd*scp)+staticvoidcxlflash_wait_for_pci_err_recovery(structcxlflash_cfg*cfg){-intrc=SUCCESS;-structScsi_Host*host=scp->device->host;-structcxlflash_cfg*cfg=(structcxlflash_cfg*)host->hostdata;-structafu*afu=cfg->afu;-intrcr=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]));--switch(cfg->state){-caseSTATE_NORMAL:-rcr=send_tmf(afu,scp,TMF_LUN_RESET);-if(unlikely(rcr))-rc=FAILED;-break;-caseSTATE_RESET:-wait_event(cfg->reset_waitq,cfg->state!=STATE_RESET);-if(cfg->state==STATE_NORMAL)-break;-/* fall through */-default:-rc=FAILED;-break;-}+structpci_dev*pdev=cfg->dev;-pr_debug("%s: returning rc=%d\n",__func__,rc);-returnrc;+if(pci_channel_offline(pdev))+wait_event_timeout(cfg->reset_waitq,+!pci_channel_offline(pdev),+CXLFLASH_PCI_ERROR_RECOVERY_TIMEOUT);}/**-*cxlflash_eh_host_reset_handler()-resetthehostadapter-*@scp:SCSIcommandfromstackidentifyinghost.-*-*Return:-*SUCCESSasdefinedinscsi/scsi.h-*FAILEDasdefinedinscsi/scsi.h+*free_mem()-freememoryassociatedwiththeAFU+*@cxlflash:Internalstructureassociatedwiththehost.*/-staticintcxlflash_eh_host_reset_handler(structscsi_cmnd*scp)+staticvoidfree_mem(structcxlflash_cfg*cfg){-intrc=SUCCESS;-intrcr=0;-structScsi_Host*host=scp->device->host;-structcxlflash_cfg*cfg=(structcxlflash_cfg*)host->hostdata;+inti;+char*buf=NULL;+structafu*afu=cfg->afu;-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]));+if(cfg->afu){+for(i=0;i<CXLFLASH_NUM_CMDS;i++){+buf=afu->cmd[i].buf;+if(!((u64)buf&(PAGE_SIZE-1)))+free_page((ulong)buf);+}-switch(cfg->state){-caseSTATE_NORMAL:-cfg->state=STATE_RESET;-scsi_block_requests(cfg->host);-cxlflash_mark_contexts_error(cfg);-rcr=cxlflash_afu_reset(cfg);-if(rcr){-rc=FAILED;-cfg->state=STATE_FAILTERM;-}else-cfg->state=STATE_NORMAL;-wake_up_all(&cfg->reset_waitq);-scsi_unblock_requests(cfg->host);-break;-caseSTATE_RESET:-wait_event(cfg->reset_waitq,cfg->state!=STATE_RESET);-if(cfg->state==STATE_NORMAL)-break;-/* fall through */-default:-rc=FAILED;-break;+free_pages((ulong)afu,get_order(sizeof(structafu)));+cfg->afu=NULL;}--pr_debug("%s: returning rc=%d\n",__func__,rc);-returnrc;}/**-*cxlflash_change_queue_depth()-changethequeuedepthforthedevice-*@sdev:SCSIdevicedestinedforqueuedepthchange.-*@qdepth:Requestedqueuedepthvaluetoset.-*-*Therequestedqueuedepthiscappedtothemaximumsupportedvalue.+*stop_afu()-stopstheAFUcommandtimersandunmapstheMMIOspace+*@cxlflash:Internalstructureassociatedwiththehost.*-*Return:Theactualqueuedepthset.+*SafetocallwithAFUinapartiallyallocated/initializedstate.*/-staticintcxlflash_change_queue_depth(structscsi_device*sdev,intqdepth)+staticvoidstop_afu(structcxlflash_cfg*cfg){+inti;+structafu*afu=cfg->afu;-if(qdepth>CXLFLASH_MAX_CMDS_PER_LUN)-qdepth=CXLFLASH_MAX_CMDS_PER_LUN;--scsi_change_queue_depth(sdev,qdepth);-returnsdev->queue_depth;-}--/**-*cxlflash_show_port_status()-queriesandpresentsthecurrentportstatus-*@dev:Genericdeviceassociatedwiththehostowningtheport.-*@attr:Deviceattributerepresentingtheport.-*@buf:BufferoflengthPAGE_SIZEtoreportbackportstatusinASCII.-*-*Return:ThesizeoftheASCIIstringreturnedin@buf.-*/-staticssize_tcxlflash_show_port_status(structdevice*dev,-structdevice_attribute*attr,-char*buf)-{-structScsi_Host*shost=class_to_shost(dev);-structcxlflash_cfg*cfg=(structcxlflash_cfg*)shost->hostdata;-structafu*afu=cfg->afu;--char*disp_status;-intrc;-u32port;-u64status;-u64*fc_regs;--rc=kstrtouint((attr->attr.name+4),10,&port);-if(rc||(port>=NUM_FC_PORTS))-return0;--fc_regs=&afu->afu_map->global.fc_regs[port][0];-status=-(readq_be(&fc_regs[FC_MTIP_STATUS/8])&FC_MTIP_STATUS_MASK);--if(status==FC_MTIP_STATUS_ONLINE)-disp_status="online";-elseif(status==FC_MTIP_STATUS_OFFLINE)-disp_status="offline";-else-disp_status="unknown";--returnsnprintf(buf,PAGE_SIZE,"%s\n",disp_status);-}--/**-*cxlflash_show_lun_mode()-presentsthecurrentLUNmodeofthehost-*@dev:Genericdeviceassociatedwiththehost.-*@attr:Deviceattributerepresentingthelunmode.-*@buf:BufferoflengthPAGE_SIZEtoreportbacktheLUNmodeinASCII.-*-*Return:ThesizeoftheASCIIstringreturnedin@buf.-*/-staticssize_tcxlflash_show_lun_mode(structdevice*dev,-structdevice_attribute*attr,char*buf)-{-structScsi_Host*shost=class_to_shost(dev);-structcxlflash_cfg*cfg=(structcxlflash_cfg*)shost->hostdata;-structafu*afu=cfg->afu;--returnsnprintf(buf,PAGE_SIZE,"%u\n",afu->internal_lun);-}--/**-*cxlflash_store_lun_mode()-setstheLUNmodeofthehost-*@dev:Genericdeviceassociatedwiththehost.-*@attr:Deviceattributerepresentingthelunmode.-*@buf:BufferoflengthPAGE_SIZEcontainingtheLUNmodeinASCII.-*@count:Lengthofdataresizingin@buf.-*-*TheCXLFlashAFUsupportsadummyLUNmodewheretheexternal-*linksandstoragearenotrequired.SpaceontheFPGAisused-*tocreate1or2smallLUNswhicharepresentedtothesystem-*asiftheywereanormalstoragedevice.Thisfeatureisuseful-*duringdevelopmentandalsoprovidesmanufacturingwithaway-*totesttheAFUwithoutanactualdevice.-*-*0=externalLUN[s](default)-*1=internalLUN(1x64K,512Bblocks,id0)-*2=internalLUN(1x64K,4Kblocks,id0)-*3=internalLUN(2x32K,512Bblocks,ids0,1)-*4=internalLUN(2x32K,4Kblocks,ids0,1)-*-*Return:ThesizeoftheASCIIstringreturnedin@buf.-*/-staticssize_tcxlflash_store_lun_mode(structdevice*dev,-structdevice_attribute*attr,-constchar*buf,size_tcount)-{-structScsi_Host*shost=class_to_shost(dev);-structcxlflash_cfg*cfg=(structcxlflash_cfg*)shost->hostdata;-structafu*afu=cfg->afu;-intrc;-u32lun_mode;--rc=kstrtouint(buf,10,&lun_mode);-if(!rc&&(lun_mode<5)&&(lun_mode!=afu->internal_lun)){-afu->internal_lun=lun_mode;-cxlflash_afu_reset(cfg);-scsi_scan_host(cfg->host);-}--returncount;-}--/**-*cxlflash_show_ioctl_version()-presentsthecurrentioctlversionofthehost-*@dev:Genericdeviceassociatedwiththehost.-*@attr:Deviceattributerepresentingtheioctlversion.-*@buf:BufferoflengthPAGE_SIZEtoreportbacktheioctlversion.-*-*Return:ThesizeoftheASCIIstringreturnedin@buf.-*/-staticssize_tcxlflash_show_ioctl_version(structdevice*dev,-structdevice_attribute*attr,-char*buf)-{-returnscnprintf(buf,PAGE_SIZE,"%u\n",DK_CXLFLASH_VERSION_0);-}--/**-*cxlflash_show_dev_mode()-presentsthecurrentmodeofthedevice-*@dev:Genericdeviceassociatedwiththedevice.-*@attr:Deviceattributerepresentingthedevicemode.-*@buf:BufferoflengthPAGE_SIZEtoreportbackthedevmodeinASCII.-*-*Return:ThesizeoftheASCIIstringreturnedin@buf.-*/-staticssize_tcxlflash_show_dev_mode(structdevice*dev,-structdevice_attribute*attr,char*buf)-{-structscsi_device*sdev=to_scsi_device(dev);--returnsnprintf(buf,PAGE_SIZE,"%s\n",-sdev->hostdata?"superpipe":"legacy");-}--/**-*cxlflash_wait_for_pci_err_recovery()-waitforerrorrecoveryduringprobe-*@cxlflash:Internalstructureassociatedwiththehost.-*/-staticvoidcxlflash_wait_for_pci_err_recovery(structcxlflash_cfg*cfg)-{-structpci_dev*pdev=cfg->dev;--if(pci_channel_offline(pdev))-wait_event_timeout(cfg->reset_waitq,-!pci_channel_offline(pdev),-CXLFLASH_PCI_ERROR_RECOVERY_TIMEOUT);-}--/*-*Hostattributes-*/-staticDEVICE_ATTR(port0,S_IRUGO,cxlflash_show_port_status,NULL);-staticDEVICE_ATTR(port1,S_IRUGO,cxlflash_show_port_status,NULL);-staticDEVICE_ATTR(lun_mode,S_IRUGO|S_IWUSR,cxlflash_show_lun_mode,-cxlflash_store_lun_mode);-staticDEVICE_ATTR(ioctl_version,S_IRUGO,cxlflash_show_ioctl_version,NULL);--staticstructdevice_attribute*cxlflash_host_attrs[]={-&dev_attr_port0,-&dev_attr_port1,-&dev_attr_lun_mode,-&dev_attr_ioctl_version,-NULL-};--/*-*Deviceattributes-*/-staticDEVICE_ATTR(mode,S_IRUGO,cxlflash_show_dev_mode,NULL);--staticstructdevice_attribute*cxlflash_dev_attrs[]={-&dev_attr_mode,-NULL-};--/*-*Hosttemplate-*/-staticstructscsi_host_templatedriver_template={-.module=THIS_MODULE,-.name=CXLFLASH_ADAPTER_NAME,-.info=cxlflash_driver_info,-.ioctl=cxlflash_ioctl,-.proc_name=CXLFLASH_NAME,-.queuecommand=cxlflash_queuecommand,-.eh_device_reset_handler=cxlflash_eh_device_reset_handler,-.eh_host_reset_handler=cxlflash_eh_host_reset_handler,-.change_queue_depth=cxlflash_change_queue_depth,-.cmd_per_lun=16,-.can_queue=CXLFLASH_MAX_CMDS,-.this_id=-1,-.sg_tablesize=SG_NONE,/* No scatter gather support. */-.max_sectors=CXLFLASH_MAX_SECTORS,-.use_clustering=ENABLE_CLUSTERING,-.shost_attrs=cxlflash_host_attrs,-.sdev_attrs=cxlflash_dev_attrs,-};--/*-*Devicedependentvalues-*/-staticstructdev_dependent_valsdev_corsa_vals={CXLFLASH_MAX_SECTORS};--/*-*PCIdevicebindingtable-*/-staticstructpci_device_idcxlflash_pci_table[]={-{PCI_VENDOR_ID_IBM,PCI_DEVICE_ID_IBM_CORSA,-PCI_ANY_ID,PCI_ANY_ID,0,0,(kernel_ulong_t)&dev_corsa_vals},-{}-};--MODULE_DEVICE_TABLE(pci,cxlflash_pci_table);--/**-*free_mem()-freememoryassociatedwiththeAFU-*@cxlflash:Internalstructureassociatedwiththehost.-*/-staticvoidfree_mem(structcxlflash_cfg*cfg)-{-inti;-char*buf=NULL;-structafu*afu=cfg->afu;--if(cfg->afu){-for(i=0;i<CXLFLASH_NUM_CMDS;i++){-buf=afu->cmd[i].buf;-if(!((u64)buf&(PAGE_SIZE-1)))-free_page((ulong)buf);-}--free_pages((ulong)afu,get_order(sizeof(structafu)));-cfg->afu=NULL;-}-}--/**-*stop_afu()-stopstheAFUcommandtimersandunmapstheMMIOspace-*@cxlflash:Internalstructureassociatedwiththehost.-*-*SafetocallwithAFUinapartiallyallocated/initializedstate.-*/-staticvoidstop_afu(structcxlflash_cfg*cfg)-{-inti;-structafu*afu=cfg->afu;--if(likely(afu)){-for(i=0;i<CXLFLASH_NUM_CMDS;i++)-complete(&afu->cmd[i].cevent);+if(likely(afu)){+for(i=0;i<CXLFLASH_NUM_CMDS;i++)+complete(&afu->cmd[i].cevent);if(likely(afu->afu_map)){cxl_psa_unmap((void*)afu->afu_map);
@@ -1631,67 +1457,13 @@ out:}/**-*cxlflash_context_reset()-timeouthandlerforAFUcommands-*@cmd:AFUcommandthattimedout.+*init_pcr()-initializetheprovisioningandcontrolregisters+*@cxlflash:Internalstructureassociatedwiththehost.*-*SendsaresettotheAFU.+*AlsosetsupfastaccesstothemappedregistersandinitializesAFU+*commandfieldsthatneverchange.*/-voidcxlflash_context_reset(structafu_cmd*cmd)-{-intnretry=0;-u64rrin=0x1;-u64room=0;-structafu*afu=cmd->parent;-ulonglock_flags;--pr_debug("%s: cmd=%p\n",__func__,cmd);--spin_lock_irqsave(&cmd->slock,lock_flags);--/* Already completed? */-if(cmd->sa.host_use_b[0]&B_DONE){-spin_unlock_irqrestore(&cmd->slock,lock_flags);-return;-}--cmd->sa.host_use_b[0]|=(B_DONE|B_ERROR|B_TIMEOUT);-spin_unlock_irqrestore(&cmd->slock,lock_flags);--/*-*Wereallywanttosendthisresetatallcosts,sospread-*outwaittimeonsuccessiveretriesforavailableroom.-*/-do{-room=readq_be(&afu->host_map->cmd_room);-atomic64_set(&afu->room,room);-if(room)-gotowrite_rrin;-udelay(nretry);-}while(nretry++<MC_ROOM_RETRY_CNT);--pr_err("%s: no cmd_room to send reset\n",__func__);-return;--write_rrin:-nretry=0;-writeq_be(rrin,&afu->host_map->ioarrin);-do{-rrin=readq_be(&afu->host_map->ioarrin);-if(rrin!=0x1)-break;-/* Double delay each time */-udelay(2^nretry);-}while(nretry++<MC_ROOM_RETRY_CNT);-}--/**-*init_pcr()-initializetheprovisioningandcontrolregisters-*@cxlflash:Internalstructureassociatedwiththehost.-*-*AlsosetsupfastaccesstothemappedregistersandinitializesAFU-*commandfieldsthatneverchange.-*/-voidinit_pcr(structcxlflash_cfg*cfg)+staticvoidinit_pcr(structcxlflash_cfg*cfg){structafu*afu=cfg->afu;structsisl_ctrl_map*ctrl_map;
@@ -1998,92 +1770,6 @@ err1:}/**-*cxlflash_send_cmd()-sendsanAFUcommand-*@afu:AFUassociatedwiththehost.-*@cmd:AFUcommandtosend.-*-*Return:-*0onsuccess-*-1onfailure-*/-intcxlflash_send_cmd(structafu*afu,structafu_cmd*cmd)-{-structcxlflash_cfg*cfg=afu->parent;-intnretry=0;-intrc=0;-u64room;-longnewval;--/*-*ThisroutineisusedbycriticaluserssuchanAFUsyncandto-*sendataskmanagementfunction(TMF).Thuswewanttoretrya-*bitbeforereturninganerror.Toavoidtheperformancepenalty-*ofMMIO,wespreadtheupdateof'room'overmultiplecommands.-*/-retry:-newval=atomic64_dec_if_positive(&afu->room);-if(!newval){-do{-room=readq_be(&afu->host_map->cmd_room);-atomic64_set(&afu->room,room);-if(room)-gotowrite_ioarrin;-udelay(nretry);-}while(nretry++<MC_ROOM_RETRY_CNT);--pr_err("%s: no cmd_room to send 0x%X\n",-__func__,cmd->rcb.cdb[0]);--gotono_room;-}elseif(unlikely(newval<0)){-/* This should be rare. i.e. Only if two threads race and-*decrementbeforetheMMIOreadisdone.Inthiscase-*justbenefitfromtheotherthreadhavingupdated-*afu->room.-*/-if(nretry++<MC_ROOM_RETRY_CNT){-udelay(nretry);-gotoretry;-}--gotono_room;-}--write_ioarrin:-writeq_be((u64)&cmd->rcb,&afu->host_map->ioarrin);-out:-pr_debug("%s: cmd=%p len=%d ea=%p rc=%d\n",__func__,cmd,-cmd->rcb.data_len,(void*)cmd->rcb.data_ea,rc);-returnrc;--no_room:-afu->read_room=true;-schedule_work(&cfg->work_q);-rc=SCSI_MLQUEUE_HOST_BUSY;-gotoout;-}--/**-*cxlflash_wait_resp()-pollsforaresponseortimeouttoasentAFUcommand-*@afu:AFUassociatedwiththehost.-*@cmd:AFUcommandthatwassent.-*/-voidcxlflash_wait_resp(structafu*afu,structafu_cmd*cmd)-{-ulongtimeout=jiffies+(cmd->rcb.timeout*2*HZ);--timeout=wait_for_completion_timeout(&cmd->cevent,timeout);-if(!timeout)-cxlflash_context_reset(cmd);--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);-}--/***cxlflash_afu_sync()-buildsandsendsanAFUsynccommand*@afu:AFUassociatedwiththehost.*@ctx_hndl_u:Identifiescontextrequestingsync.
@@ -2121,7 +1807,7 @@ int cxlflash_afu_sync(struct afu *afu, ctx_hndl_t ctx_hndl_u,mutex_lock(&sync_active);retry:-cmd=cxlflash_cmd_checkout(afu);+cmd=cmd_checkout(afu);if(unlikely(!cmd)){retry_cnt++;udelay(1000*retry_cnt);
@@ -2150,11 +1836,11 @@ retry:*((u16*)&cmd->rcb.cdb[2])=swab16(ctx_hndl_u);*((u32*)&cmd->rcb.cdb[4])=swab32(res_hndl_u);-rc=cxlflash_send_cmd(afu,cmd);+rc=send_cmd(afu,cmd);if(unlikely(rc))gotoout;-cxlflash_wait_resp(afu,cmd);+wait_resp(afu,cmd);/* set on timeout */if(unlikely((cmd->sa.ioasc!=0)||
@@ -2163,20 +1849,20 @@ retry:out:mutex_unlock(&sync_active);if(cmd)-cxlflash_cmd_checkin(cmd);+cmd_checkin(cmd);pr_debug("%s: returning rc=%d\n",__func__,rc);returnrc;}/**-*cxlflash_afu_reset()-resetstheAFU-*@cxlflash:Internalstructureassociatedwiththehost.+*afu_reset()-resetstheAFU+*@cfg:Internalstructureassociatedwiththehost.**Return:*0onsuccess*Afailurevaluefrominternalservices.*/-intcxlflash_afu_reset(structcxlflash_cfg*cfg)+staticintafu_reset(structcxlflash_cfg*cfg){intrc=0;/* Stop the context before the reset. Since the context is
@@ -2192,6 +1878,320 @@ int cxlflash_afu_reset(struct cxlflash_cfg *cfg)}/**+*cxlflash_eh_device_reset_handler()-resetasingleLUN+*@scp:SCSIcommandtosend.+*+*Return:+*SUCCESSasdefinedinscsi/scsi.h+*FAILEDasdefinedinscsi/scsi.h+*/+staticintcxlflash_eh_device_reset_handler(structscsi_cmnd*scp)+{+intrc=SUCCESS;+structScsi_Host*host=scp->device->host;+structcxlflash_cfg*cfg=(structcxlflash_cfg*)host->hostdata;+structafu*afu=cfg->afu;+intrcr=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]));++switch(cfg->state){+caseSTATE_NORMAL:+rcr=send_tmf(afu,scp,TMF_LUN_RESET);+if(unlikely(rcr))+rc=FAILED;+break;+caseSTATE_RESET:+wait_event(cfg->reset_waitq,cfg->state!=STATE_RESET);+if(cfg->state==STATE_NORMAL)+break;+/* fall through */+default:+rc=FAILED;+break;+}++pr_debug("%s: returning rc=%d\n",__func__,rc);+returnrc;+}++/**+*cxlflash_eh_host_reset_handler()-resetthehostadapter+*@scp:SCSIcommandfromstackidentifyinghost.+*+*Return:+*SUCCESSasdefinedinscsi/scsi.h+*FAILEDasdefinedinscsi/scsi.h+*/+staticintcxlflash_eh_host_reset_handler(structscsi_cmnd*scp)+{+intrc=SUCCESS;+intrcr=0;+structScsi_Host*host=scp->device->host;+structcxlflash_cfg*cfg=(structcxlflash_cfg*)host->hostdata;++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]));++switch(cfg->state){+caseSTATE_NORMAL:+cfg->state=STATE_RESET;+scsi_block_requests(cfg->host);+cxlflash_mark_contexts_error(cfg);+rcr=afu_reset(cfg);+if(rcr){+rc=FAILED;+cfg->state=STATE_FAILTERM;+}else+cfg->state=STATE_NORMAL;+wake_up_all(&cfg->reset_waitq);+scsi_unblock_requests(cfg->host);+break;+caseSTATE_RESET:+wait_event(cfg->reset_waitq,cfg->state!=STATE_RESET);+if(cfg->state==STATE_NORMAL)+break;+/* fall through */+default:+rc=FAILED;+break;+}++pr_debug("%s: returning rc=%d\n",__func__,rc);+returnrc;+}++/**+*cxlflash_change_queue_depth()-changethequeuedepthforthedevice+*@sdev:SCSIdevicedestinedforqueuedepthchange.+*@qdepth:Requestedqueuedepthvaluetoset.+*+*Therequestedqueuedepthiscappedtothemaximumsupportedvalue.+*+*Return:Theactualqueuedepthset.+*/+staticintcxlflash_change_queue_depth(structscsi_device*sdev,intqdepth)+{++if(qdepth>CXLFLASH_MAX_CMDS_PER_LUN)+qdepth=CXLFLASH_MAX_CMDS_PER_LUN;++scsi_change_queue_depth(sdev,qdepth);+returnsdev->queue_depth;+}++/**+*cxlflash_show_port_status()-queriesandpresentsthecurrentportstatus+*@dev:Genericdeviceassociatedwiththehostowningtheport.+*@attr:Deviceattributerepresentingtheport.+*@buf:BufferoflengthPAGE_SIZEtoreportbackportstatusinASCII.+*+*Return:ThesizeoftheASCIIstringreturnedin@buf.+*/+staticssize_tcxlflash_show_port_status(structdevice*dev,+structdevice_attribute*attr,+char*buf)+{+structScsi_Host*shost=class_to_shost(dev);+structcxlflash_cfg*cfg=(structcxlflash_cfg*)shost->hostdata;+structafu*afu=cfg->afu;++char*disp_status;+intrc;+u32port;+u64status;+u64*fc_regs;++rc=kstrtouint((attr->attr.name+4),10,&port);+if(rc||(port>=NUM_FC_PORTS))+return0;++fc_regs=&afu->afu_map->global.fc_regs[port][0];+status=+(readq_be(&fc_regs[FC_MTIP_STATUS/8])&FC_MTIP_STATUS_MASK);++if(status==FC_MTIP_STATUS_ONLINE)+disp_status="online";+elseif(status==FC_MTIP_STATUS_OFFLINE)+disp_status="offline";+else+disp_status="unknown";++returnsnprintf(buf,PAGE_SIZE,"%s\n",disp_status);+}++/**+*cxlflash_show_lun_mode()-presentsthecurrentLUNmodeofthehost+*@dev:Genericdeviceassociatedwiththehost.+*@attr:Deviceattributerepresentingthelunmode.+*@buf:BufferoflengthPAGE_SIZEtoreportbacktheLUNmodeinASCII.+*+*Return:ThesizeoftheASCIIstringreturnedin@buf.+*/+staticssize_tcxlflash_show_lun_mode(structdevice*dev,+structdevice_attribute*attr,char*buf)+{+structScsi_Host*shost=class_to_shost(dev);+structcxlflash_cfg*cfg=(structcxlflash_cfg*)shost->hostdata;+structafu*afu=cfg->afu;++returnsnprintf(buf,PAGE_SIZE,"%u\n",afu->internal_lun);+}++/**+*cxlflash_store_lun_mode()-setstheLUNmodeofthehost+*@dev:Genericdeviceassociatedwiththehost.+*@attr:Deviceattributerepresentingthelunmode.+*@buf:BufferoflengthPAGE_SIZEcontainingtheLUNmodeinASCII.+*@count:Lengthofdataresizingin@buf.+*+*TheCXLFlashAFUsupportsadummyLUNmodewheretheexternal+*linksandstoragearenotrequired.SpaceontheFPGAisused+*tocreate1or2smallLUNswhicharepresentedtothesystem+*asiftheywereanormalstoragedevice.Thisfeatureisuseful+*duringdevelopmentandalsoprovidesmanufacturingwithaway+*totesttheAFUwithoutanactualdevice.+*+*0=externalLUN[s](default)+*1=internalLUN(1x64K,512Bblocks,id0)+*2=internalLUN(1x64K,4Kblocks,id0)+*3=internalLUN(2x32K,512Bblocks,ids0,1)+*4=internalLUN(2x32K,4Kblocks,ids0,1)+*+*Return:ThesizeoftheASCIIstringreturnedin@buf.+*/+staticssize_tcxlflash_store_lun_mode(structdevice*dev,+structdevice_attribute*attr,+constchar*buf,size_tcount)+{+structScsi_Host*shost=class_to_shost(dev);+structcxlflash_cfg*cfg=(structcxlflash_cfg*)shost->hostdata;+structafu*afu=cfg->afu;+intrc;+u32lun_mode;++rc=kstrtouint(buf,10,&lun_mode);+if(!rc&&(lun_mode<5)&&(lun_mode!=afu->internal_lun)){+afu->internal_lun=lun_mode;+afu_reset(cfg);+scsi_scan_host(cfg->host);+}++returncount;+}++/**+*cxlflash_show_ioctl_version()-presentsthehostscurrentioctlversion+*@dev:Genericdeviceassociatedwiththehost.+*@attr:Deviceattributerepresentingtheioctlversion.+*@buf:BufferoflengthPAGE_SIZEtoreportbacktheioctlversion.+*+*Return:ThesizeoftheASCIIstringreturnedin@buf.+*/+staticssize_tcxlflash_show_ioctl_version(structdevice*dev,+structdevice_attribute*attr,+char*buf)+{+returnscnprintf(buf,PAGE_SIZE,"%u\n",DK_CXLFLASH_VERSION_0);+}++/**+*cxlflash_show_dev_mode()-presentsthecurrentmodeofthedevice+*@dev:Genericdeviceassociatedwiththedevice.+*@attr:Deviceattributerepresentingthedevicemode.+*@buf:BufferoflengthPAGE_SIZEtoreportbackthedevmodeinASCII.+*+*Return:ThesizeoftheASCIIstringreturnedin@buf.+*/+staticssize_tcxlflash_show_dev_mode(structdevice*dev,+structdevice_attribute*attr,char*buf)+{+structscsi_device*sdev=to_scsi_device(dev);++returnsnprintf(buf,PAGE_SIZE,"%s\n",+sdev->hostdata?"superpipe":"legacy");+}++/*+*Hostattributes+*/+staticDEVICE_ATTR(port0,S_IRUGO,cxlflash_show_port_status,NULL);+staticDEVICE_ATTR(port1,S_IRUGO,cxlflash_show_port_status,NULL);+staticDEVICE_ATTR(lun_mode,S_IRUGO|S_IWUSR,cxlflash_show_lun_mode,+cxlflash_store_lun_mode);+staticDEVICE_ATTR(ioctl_version,S_IRUGO,cxlflash_show_ioctl_version,NULL);++staticstructdevice_attribute*cxlflash_host_attrs[]={+&dev_attr_port0,+&dev_attr_port1,+&dev_attr_lun_mode,+&dev_attr_ioctl_version,+NULL+};++/*+*Deviceattributes+*/+staticDEVICE_ATTR(mode,S_IRUGO,cxlflash_show_dev_mode,NULL);++staticstructdevice_attribute*cxlflash_dev_attrs[]={+&dev_attr_mode,+NULL+};++/*+*Hosttemplate+*/+staticstructscsi_host_templatedriver_template={+.module=THIS_MODULE,+.name=CXLFLASH_ADAPTER_NAME,+.info=cxlflash_driver_info,+.ioctl=cxlflash_ioctl,+.proc_name=CXLFLASH_NAME,+.queuecommand=cxlflash_queuecommand,+.eh_device_reset_handler=cxlflash_eh_device_reset_handler,+.eh_host_reset_handler=cxlflash_eh_host_reset_handler,+.change_queue_depth=cxlflash_change_queue_depth,+.cmd_per_lun=16,+.can_queue=CXLFLASH_MAX_CMDS,+.this_id=-1,+.sg_tablesize=SG_NONE,/* No scatter gather support. */+.max_sectors=CXLFLASH_MAX_SECTORS,+.use_clustering=ENABLE_CLUSTERING,+.shost_attrs=cxlflash_host_attrs,+.sdev_attrs=cxlflash_dev_attrs,+};++/*+*Devicedependentvalues+*/+staticstructdev_dependent_valsdev_corsa_vals={CXLFLASH_MAX_SECTORS};++/*+*PCIdevicebindingtable+*/+staticstructpci_device_idcxlflash_pci_table[]={+{PCI_VENDOR_ID_IBM,PCI_DEVICE_ID_IBM_CORSA,+PCI_ANY_ID,PCI_ANY_ID,0,0,(kernel_ulong_t)&dev_corsa_vals},+{}+};++MODULE_DEVICE_TABLE(pci,cxlflash_pci_table);++/***cxlflash_worker_thread()-workthreadhandlerfortheAFU*@work:Workstructurecontainedwithincxlflashassociatedwithhost.*
From: Matthew R. Ochs <hidden> Date: 2015-09-25 23:16:34
Implement the following suggestions and add two new attributes
to allow for debugging the port LUN table.
- use scnprintf() instead of snprintf()
- use DEVICE_ATTR_RO and DEVICE_ATTR_RW
Suggested-by: Shane Seymour <redacted>
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
Reviewed-by: Brian King <redacted>
---
drivers/scsi/cxlflash/main.c | 180 +++++++++++++++++++++++++++++++++----------
1 file changed, 138 insertions(+), 42 deletions(-)
From: Matthew R. Ochs <hidden> Date: 2015-09-25 23:17:16
During run-time the driver can be very chatty and spam the system
kernel log. Various print statements can be limited and/or moved
to development-only mode. Additionally, numerous prints can be
converted to trace the corresponding device.
The following changes were made:
- pr_debug to pr_devel
- pr_debug to pr_debug_ratelimited
- pr_err to dev_err
- pr_debug to dev_dbg
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
Reviewed-by: Brian King <redacted>
Conflicts:
drivers/scsi/cxlflash/main.c
---
drivers/scsi/cxlflash/main.c | 109 +++++++++++++++++++++++--------------------
1 file changed, 59 insertions(+), 50 deletions(-)
@@ -240,9 +240,9 @@ static void cmd_complete(struct afu_cmd *cmd)cmd_is_tmf=cmd->cmd_tmf;cmd_checkin(cmd);/* Don't use cmd after here */-pr_debug("%s: calling scsi_set_resid, scp=%p "-"result=%X resid=%d\n",__func__,-scp,scp->result,resid);+pr_debug_ratelimited("%s: calling scsi_done scp=%p result=%X "+"ioasc=%d\n",__func__,scp,scp->result,+cmd->sa.ioasc);scsi_set_resid(scp,resid);scsi_dma_unmap(scp);
@@ -417,12 +417,13 @@ static int send_tmf(struct afu *afu, struct scsi_cmnd *scp, u64 tmfcmd)shortlflag=0;structScsi_Host*host=scp->device->host;structcxlflash_cfg*cfg=(structcxlflash_cfg*)host->hostdata;+structdevice*dev=&cfg->dev->dev;ulonglock_flags;intrc=0;cmd=cmd_checkout(afu);if(unlikely(!cmd)){-pr_err("%s: could not get a free command\n",__func__);+dev_err(dev,"%s: could not get a free command\n",__func__);rc=SCSI_MLQUEUE_HOST_BUSY;gotoout;}
@@ -502,13 +503,14 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp)shortlflag=0;intrc=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_ratelimited(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]));/* If a Task Management Function is active, wait for it to complete*beforecontinuingwithregularcommands.
@@ -523,13 +525,11 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp)switch(cfg->state){caseSTATE_RESET:-dev_dbg_ratelimited(&cfg->dev->dev,"%s: device is in reset!\n",-__func__);+dev_dbg_ratelimited(dev,"%s: device is in reset!\n",__func__);rc=SCSI_MLQUEUE_HOST_BUSY;gotoout;caseSTATE_FAILTERM:-dev_dbg_ratelimited(&cfg->dev->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;
@@ -540,7 +540,7 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp)cmd=cmd_checkout(afu);if(unlikely(!cmd)){-pr_err("%s: could not get a free command\n",__func__);+dev_err(dev,"%s: could not get a free command\n",__func__);rc=SCSI_MLQUEUE_HOST_BUSY;gotoout;}
@@ -657,9 +658,10 @@ static void term_mc(struct cxlflash_cfg *cfg, enum undo_level level){intrc=0;structafu*afu=cfg->afu;+structdevice*dev=&cfg->dev->dev;if(!afu||!cfg->mcctx){-pr_err("%s: returning from term_mc with NULL afu or MC\n",+dev_err(dev,"%s: returning from term_mc with NULL afu or MC\n",__func__);return;}
@@ -755,6 +757,7 @@ static int alloc_mem(struct cxlflash_cfg *cfg)intrc=0;inti;char*buf=NULL;+structdevice*dev=&cfg->dev->dev;/* This allocation is about 12K, i.e. only 1 64k page*andupto44kpages
@@ -762,8 +765,8 @@ static int alloc_mem(struct cxlflash_cfg *cfg)cfg->afu=(void*)__get_free_pages(GFP_KERNEL|__GFP_ZERO,get_order(sizeof(structafu)));if(unlikely(!cfg->afu)){-pr_err("%s: cannot get %d free pages\n",-__func__,get_order(sizeof(structafu)));+dev_err(dev,"%s: cannot get %d free pages\n",+__func__,get_order(sizeof(structafu)));rc=-ENOMEM;gotoout;}
@@ -1310,8 +1313,8 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data)port=info->port;-pr_err("%s: FC Port %d -> %s, fc_status 0x%08llX\n",-__func__,port,info->desc,+dev_err(dev,"%s: FC Port %d -> %s, fc_status 0x%08llX\n",+__func__,port,info->desc,readq_be(&global->fc_regs[port][FC_STATUS/8]));/*
@@ -1319,8 +1322,8 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data)*againifclearedbeforeorw/oareset*/if(info->action&LINK_RESET){-pr_err("%s: FC Port %d: resetting link\n",-__func__,port);+dev_err(dev,"%s: FC Port %d: resetting link\n",+__func__,port);cfg->lr_state=LINK_RESET_REQUIRED;cfg->lr_port=port;schedule_work(&cfg->work_q);
@@ -1334,8 +1337,8 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data)*shouldbethesameandtracingoneissufficient.*/-pr_err("%s: fc %d: clearing fc_error 0x%08llX\n",-__func__,port,reg);+dev_err(dev,"%s: fc %d: clearing fc_error 0x%08llX\n",+__func__,port,reg);writeq_be(reg,&global->fc_regs[port][FC_ERROR/8]);writeq_be(0,&global->fc_regs[port][FC_ERRCAP/8]);
@@ -1387,7 +1390,7 @@ static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[])/* Get the VPD data from the device */vpd_size=pci_read_vpd(dev,0,sizeof(vpd_data),vpd_data);if(unlikely(vpd_size<=0)){-pr_err("%s: Unable to read VPD (size = %ld)\n",+dev_err(&dev->dev,"%s: Unable to read VPD (size = %ld)\n",__func__,vpd_size);rc=-ENODEV;gotoout;
@@ -1397,7 +1400,8 @@ static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[])ro_start=pci_vpd_find_tag(vpd_data,0,vpd_size,PCI_VPD_LRDT_RO_DATA);if(unlikely(ro_start<0)){-pr_err("%s: VPD Read-only data not found\n",__func__);+dev_err(&dev->dev,"%s: VPD Read-only data not found\n",+__func__);rc=-ENODEV;gotoout;}
@@ -1426,8 +1430,8 @@ static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[])i=pci_vpd_find_info_keyword(vpd_data,i,j,wwpn_vpd_tags[k]);if(unlikely(i<0)){-pr_err("%s: Port %d WWPN not found in VPD\n",-__func__,k);+dev_err(&dev->dev,"%s: Port %d WWPN not found "+"in VPD\n",__func__,k);rc=-ENODEV;gotoout;}
@@ -1435,7 +1439,8 @@ static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[])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))){-pr_err("%s: Port %d WWPN incomplete or VPD corrupt\n",+dev_err(&dev->dev,"%s: Port %d WWPN incomplete or "+"VPD corrupt\n",__func__,k);rc=-ENODEV;gotoout;
@@ -1444,8 +1449,8 @@ static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[])memcpy(tmp_buf,&vpd_data[i],WWPN_LEN);rc=kstrtoul(tmp_buf,WWPN_LEN,(ulong*)&wwpn[k]);if(unlikely(rc)){-pr_err("%s: Fail to convert port %d WWPN to integer\n",-__func__,k);+dev_err(&dev->dev,"%s: Fail to convert port %d WWPN "+"to integer\n",__func__,k);rc=-ENODEV;gotoout;}
@@ -1509,7 +1515,7 @@ static int init_global(struct cxlflash_cfg *cfg)rc=read_vpd(cfg,&wwpn[0]);if(rc){-pr_err("%s: could not read vpd rc=%d\n",__func__,rc);+dev_err(dev,"%s: could not read vpd rc=%d\n",__func__,rc);gotoout;}
@@ -1552,7 +1558,7 @@ static int init_global(struct cxlflash_cfg *cfg)afu_set_wwpn(afu,i,&afu->afu_map->global.fc_regs[i][0],wwpn[i])){-pr_err("%s: failed to set WWPN on port %d\n",+dev_err(dev,"%s: failed to set WWPN on port %d\n",__func__,i);rc=-EIO;gotoout;
@@ -1795,6 +1801,7 @@ int cxlflash_afu_sync(struct afu *afu, ctx_hndl_t ctx_hndl_u,res_hndl_tres_hndl_u,u8mode){structcxlflash_cfg*cfg=afu->parent;+structdevice*dev=&cfg->dev->dev;structafu_cmd*cmd=NULL;intrc=0;intretry_cnt=0;
@@ -1813,7 +1820,7 @@ retry:udelay(1000*retry_cnt);if(retry_cnt<MC_RETRY_CNT)gotoretry;-pr_err("%s: could not get a free command\n",__func__);+dev_err(dev,"%s: could not get a free command\n",__func__);rc=-1;gotoout;}
@@ -2314,7 +2322,8 @@ static void cxlflash_worker_thread(struct work_struct *work)if(cfg->lr_state==LINK_RESET_REQUIRED){port=cfg->lr_port;if(port<0)-pr_err("%s: invalid port index %d\n",__func__,port);+dev_err(dev,"%s: invalid port index %d\n",+__func__,port);else{spin_unlock_irqrestore(cfg->host->host_lock,lock_flags);
@@ -2419,7 +2428,7 @@ static int cxlflash_probe(struct pci_dev *pdev,*/phys_dev=cxl_get_phys_dev(pdev);if(!dev_is_pci(phys_dev)){-pr_err("%s: not a pci dev\n",__func__);+dev_err(&pdev->dev,"%s: not a pci dev\n",__func__);rc=-ENODEV;gotoout_remove;}
From: Matthew R. Ochs <hidden> Date: 2015-09-25 23:17:19
The resid is incorrectly set which can lead to unnecessary retry
attempts by the stack. This is due to resid _always_ being set
using a value returned from the adapter. Instead, the value
should only be interpreted and set when in an underrun scenario.
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
Reviewed-by: Brian King <redacted>
---
drivers/scsi/cxlflash/main.c | 20 ++++++++------------
1 file changed, 8 insertions(+), 12 deletions(-)
@@ -158,8 +160,7 @@ static void process_cmd_err(struct afu_cmd *cmd, struct scsi_cmnd *scp)/* If the SISL_RC_FLAGS_OVERRUN flag was set,*thenwewillhandlethiserrorelsewhere.*Ifnotthenwemusthandleithere.-*ThisisprobablyanAFUbug.Wewill-*attemptaretrytoseeifthatresolvesit.+*ThisisprobablyanAFUbug.*/scp->result=(DID_ERROR<<16);}
@@ -183,7 +184,7 @@ static void process_cmd_err(struct afu_cmd *cmd, struct scsi_cmnd *scp)/* We have an AFU error */switch(ioasa->rc.afu_rc){caseSISL_AFU_RC_NO_CHANNELS:-scp->result=(DID_MEDIUM_ERROR<<16);+scp->result=(DID_NO_CONNECT<<16);break;caseSISL_AFU_RC_DATA_DMA_ERR:switch(ioasa->afu_extra){
@@ -229,14 +229,11 @@ static void cmd_complete(struct afu_cmd *cmd)if(cmd->rcb.scp){scp=cmd->rcb.scp;-if(unlikely(cmd->sa.rc.afu_rc||-cmd->sa.rc.scsi_rc||-cmd->sa.rc.fc_rc))+if(unlikely(cmd->sa.ioasc))process_cmd_err(cmd,scp);elsescp->result=(DID_OK<<16);-resid=cmd->sa.resid;cmd_is_tmf=cmd->cmd_tmf;cmd_checkin(cmd);/* Don't use cmd after here */
From: Matthew R. Ochs <hidden> Date: 2015-09-25 23:17:28
Following a link up event, the LUNs available to the host may
have changed. Without rescanning the host, the LUN topology is
unknown to the user. In such a state, the user would be unable
to locate provisioned resources.
To remedy, the host should be rescanned after a link up event.
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
Reviewed-by: Brian King <redacted>
Conflicts:
drivers/scsi/cxlflash/common.h
---
drivers/scsi/cxlflash/common.h | 1 +
drivers/scsi/cxlflash/main.c | 17 +++++++++++++----
drivers/scsi/cxlflash/main.h | 1 +
3 files changed, 15 insertions(+), 4 deletions(-)
From: Matthew R. Ochs <hidden> Date: 2015-09-25 23:17:36
A bug was introduced earlier in the development cycle when cleaning
up logic statements. Instead of skipping bits that are not set, set
bits are skipped, causing async interrupts to not be handled correctly.
To fix, simply add back in the proper evaluation for an unset bit.
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
Reviewed-by: Brian King <redacted>
---
drivers/scsi/cxlflash/main.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
@@ -1315,7 +1315,7 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data)/* check each bit that is on */for(i=0;reg_unmasked;i++,reg_unmasked=(reg_unmasked>>1)){info=find_ainfo(1ULL<<i);-if((reg_unmasked&0x1)||!info)+if(((reg_unmasked&0x1)==0)||!info)continue;port=info->port;
From: Matthew R. Ochs <hidden> Date: 2015-09-25 23:17:41
At present, both ports must be online for the device to
configure properly. Remove this dependency and the unnecessary
internal LUN override logic as well. Additionally, as a refactoring
measure, change the return code variable name to match that used
throughout the driver.
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
Reviewed-by: Brian King <redacted>
---
drivers/scsi/cxlflash/main.c | 23 ++++++++---------------
1 file changed, 8 insertions(+), 15 deletions(-)
@@ -1038,33 +1038,26 @@ static int afu_set_wwpn(struct afu *afu, int port, u64 *fc_regs, u64 wwpn)FC_PORT_STATUS_RETRY_CNT)){pr_debug("%s: wait on port %d to go offline timed out\n",__func__,port);-ret=-1;/* but continue on to leave the port back online */+rc=-1;/* but continue on to leave the port back online */}-if(ret==0)+if(rc==0)writeq_be(wwpn,&fc_regs[FC_PNAME/8]);+/* Always return success after programming WWPN */+rc=0;+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);-ret=-1;--/*-*Overrideforinternallun!!!-*/-if(afu->internal_lun){-pr_debug("%s: Overriding port %d online timeout!!!\n",-__func__,port);-ret=0;-}}-pr_debug("%s: returning rc=%d\n",__func__,ret);+pr_debug("%s: returning rc=%d\n",__func__,rc);-returnret;+returnrc;}/**
From: Matthew R. Ochs <hidden> Date: 2015-09-25 23:17:45
Borrowing the TMF waitq's spinlock causes a stall condition when
waiting for the TMF to complete. To remedy, introduce our own spin
lock to serialize TMF and use the appropriate wait services.
Also add a timeout while waiting for a TMF completion. When a TMF
times out, report back a failure such that a bigger hammer reset
can occur.
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
Reviewed-by: Brian King <redacted>
---
drivers/scsi/cxlflash/common.h | 1 +
drivers/scsi/cxlflash/main.c | 55 +++++++++++++++++++++++++-----------------
2 files changed, 34 insertions(+), 22 deletions(-)
@@ -428,15 +428,15 @@ static int send_tmf(struct afu *afu, struct scsi_cmnd *scp, u64 tmfcmd)gotoout;}-/* If a Task Management Function is active, do not send one more.-*/-spin_lock_irqsave(&cfg->tmf_waitq.lock,lock_flags);+/* When Task Management Function is active do not send another */+spin_lock_irqsave(&cfg->tmf_slock,lock_flags);if(cfg->tmf_active)-wait_event_interruptible_locked_irq(cfg->tmf_waitq,-!cfg->tmf_active);+wait_event_interruptible_lock_irq(cfg->tmf_waitq,+!cfg->tmf_active,+cfg->tmf_slock);cfg->tmf_active=true;cmd->cmd_tmf=true;-spin_unlock_irqrestore(&cfg->tmf_waitq.lock,lock_flags);+spin_unlock_irqrestore(&cfg->tmf_slock,lock_flags);cmd->rcb.ctx_id=afu->ctx_hndl;cmd->rcb.port_sel=port_sel;
@@ -512,16 +521,17 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp)get_unaligned_be32(&((u32*)scp->cmnd)[2]),get_unaligned_be32(&((u32*)scp->cmnd)[3]));-/* If a Task Management Function is active, wait for it to complete+/*+*IfaTaskManagementFunctionisactive,waitforittocomplete*beforecontinuingwithregularcommands.*/-spin_lock_irqsave(&cfg->tmf_waitq.lock,lock_flags);+spin_lock_irqsave(&cfg->tmf_slock,lock_flags);if(cfg->tmf_active){-spin_unlock_irqrestore(&cfg->tmf_waitq.lock,lock_flags);+spin_unlock_irqrestore(&cfg->tmf_slock,lock_flags);rc=SCSI_MLQUEUE_HOST_BUSY;gotoout;}-spin_unlock_irqrestore(&cfg->tmf_waitq.lock,lock_flags);+spin_unlock_irqrestore(&cfg->tmf_slock,lock_flags);switch(cfg->state){caseSTATE_RESET:
@@ -713,11 +723,12 @@ static void cxlflash_remove(struct pci_dev *pdev)/* If a Task Management Function is active, wait for it to complete*beforecontinuingwithremove.*/-spin_lock_irqsave(&cfg->tmf_waitq.lock,lock_flags);+spin_lock_irqsave(&cfg->tmf_slock,lock_flags);if(cfg->tmf_active)-wait_event_interruptible_locked_irq(cfg->tmf_waitq,-!cfg->tmf_active);-spin_unlock_irqrestore(&cfg->tmf_waitq.lock,lock_flags);+wait_event_interruptible_lock_irq(cfg->tmf_waitq,+!cfg->tmf_active,+cfg->tmf_slock);+spin_unlock_irqrestore(&cfg->tmf_slock,lock_flags);cfg->state=STATE_FAILTERM;cxlflash_stop_term_user_contexts(cfg);
From: Matthew R. Ochs <hidden> Date: 2015-09-25 23:17:47
The AFU version is stored as a non-terminated string of bytes within
a 64-bit little-endian register. Presently the value is read directly
(no MMIO accessor) and is stored in a buffer that is not big enough
to contain a NULL terminator. Additionally the version obtained is not
evaluated against a known value to prevent usage with unsupported AFUs.
All of these deficiencies can lead to a variety of problems.
To remedy, use the correct MMIO accessor to read the version value into
a null-terminated buffer and add a check to prevent an incompatible AFU
from being used with this driver.
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
Reviewed-by: Brian King <redacted>
---
drivers/scsi/cxlflash/common.h | 2 +-
drivers/scsi/cxlflash/main.c | 18 ++++++++++++------
drivers/scsi/cxlflash/sislite.h | 2 +-
3 files changed, 14 insertions(+), 8 deletions(-)
@@ -179,7 +179,7 @@ struct afu {u32cmd_couts;/* Number of command checkouts */u32internal_lun;/* User-desired LUN mode for this AFU */-charversion[8];+charversion[16];u64interface_version;structcxlflash_cfg*parent;/* Pointer back to parent cxlflash_cfg */
@@ -1751,14 +1751,20 @@ static int init_afu(struct cxlflash_cfg *cfg)gotoerr1;}-/* don't byte reverse on reading afu_version, else the string form */-/* will be backwards */-reg=afu->afu_map->global.regs.afu_version;-memcpy(afu->version,®,8);+/* No byte reverse on reading afu_version or string will be backwards */+reg=readq(&afu->afu_map->global.regs.afu_version);+memcpy(afu->version,®,sizeof(reg));afu->interface_version=readq_be(&afu->afu_map->global.regs.interface_version);-pr_debug("%s: afu version %s, interface version 0x%llX\n",-__func__,afu->version,afu->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,+afu->interface_version);+rc=-EINVAL;+gotoerr1;+}else+pr_debug("%s: afu version %s, interface version 0x%llX\n",+__func__,afu->version,afu->interface_version);rc=start_afu(cfg);if(rc){
From: Matthew R. Ochs <hidden> Date: 2015-09-25 23:17:53
Currently, scsi_host_put() is being called prematurely in the
remove path and is missing entirely in an error cleanup path.
The former can lead to memory being freed too early with
subsequent access potentially corrupting data whilst the former
would result in a memory leak.
Move the usage on remove to be the last cleanup action taken
and introduce a call to scsi_host_put() in the one initialization
error path that does not use remove to cleanup.
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
Reviewed-by: Brian King <redacted>
---
drivers/scsi/cxlflash/main.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
From: Matthew R. Ochs <hidden> Date: 2015-09-25 23:17:58
The workq can process work in parallel with a remove event, leading
to a condition where the workq handler can access freed memory.
To remedy, the workq should be terminated prior to freeing memory. Move
the termination call earlier in remove and use cancel_work_sync() instead
of flush_work() as there is not a need to process any scheduled work when
shutting down.
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
Reviewed-by: Brian King <redacted>
---
drivers/scsi/cxlflash/main.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
From: Matthew R. Ochs <hidden> Date: 2015-09-25 23:18:58
When the device reset handler is entered while a reset operation
is taking place, the handler exits without actually sending a
reset (TMF) to the targeted device. This behavior is incorrect
as the device is not reset. Further complicating matters is the
fact that a success is returned even when the TMF was not sent.
To fix, the state is rechecked after coming out of the reset
state. When the state is normal, a TMF will be sent out.
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
Reviewed-by: Brian King <redacted>
---
drivers/scsi/cxlflash/main.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
@@ -1920,6 +1920,7 @@ static int cxlflash_eh_device_reset_handler(struct scsi_cmnd *scp)get_unaligned_be32(&((u32*)scp->cmnd)[2]),get_unaligned_be32(&((u32*)scp->cmnd)[3]));+retry:switch(cfg->state){caseSTATE_NORMAL:rcr=send_tmf(afu,scp,TMF_LUN_RESET);
@@ -1928,9 +1929,7 @@ static int cxlflash_eh_device_reset_handler(struct scsi_cmnd *scp)break;caseSTATE_RESET:wait_event(cfg->reset_waitq,cfg->state!=STATE_RESET);-if(cfg->state==STATE_NORMAL)-break;-/* fall through */+gotoretry;default:rc=FAILED;break;
From: Matthew R. Ochs <hidden> Date: 2015-09-25 23:19:27
The host reset handler is called with I/O already blocked, thus
there is no need to explicitly block and unblock I/O in the handler.
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
Reviewed-by: Brian King <redacted>
---
drivers/scsi/cxlflash/main.c | 2 --
1 file changed, 2 deletions(-)
From: Matthew R. Ochs <hidden> Date: 2015-09-25 23:19:30
Sparse uncovered several errors with MMIO operations (accessing
directly) and handling endianness. These can cause issues when
running in different environments.
Introduce __iomem and proper endianness tags/swaps where
appropriate to make driver sparse clean.
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
Reviewed-by: Brian King <redacted>
---
drivers/scsi/cxlflash/common.h | 10 +++++-----
drivers/scsi/cxlflash/main.c | 25 +++++++++++++------------
drivers/scsi/cxlflash/superpipe.c | 6 +++---
drivers/scsi/cxlflash/superpipe.h | 2 +-
drivers/scsi/cxlflash/vlun.c | 4 ++--
5 files changed, 24 insertions(+), 23 deletions(-)
@@ -1755,7 +1756,7 @@ static int init_afu(struct cxlflash_cfg *cfg)dev_err(dev,"%s: call to start_afu failed, rc=%d!\n",__func__,rc);term_mc(cfg,UNDO_START);-cxl_psa_unmap((void*)afu->afu_map);+cxl_psa_unmap((void__iomem*)afu->afu_map);afu->afu_map=NULL;gotoerr1;}
@@ -1835,8 +1836,8 @@ retry:cmd->rcb.cdb[1]=mode;/* The cdb is aligned, no unaligned accessors required */-*((u16*)&cmd->rcb.cdb[2])=swab16(ctx_hndl_u);-*((u32*)&cmd->rcb.cdb[4])=swab32(res_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);if(unlikely(rc))
From: Matthew R. Ochs <hidden> Date: 2015-09-25 23:19:36
The process_sense() routine can perform a read capacity which
can take some time to complete. If an EEH occurs while waiting
on the read capacity, the EEH handler is unable to obtain the
context's mutex in order to put the context in an error state.
The EEH handler will sit and wait until the context is free,
but this wait can last longer than the EEH handler tolerates,
leading to a failed recovery.
To address this issue, make the context unavailable to new,
non-system owned threads and release the context while calling
into process_sense(). After returning from process_sense() the
context mutex is reacquired and the context is made available
again. The context can be safely moved to the error state if
needed during the unavailable window as no other threads will
hold its reference.
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
Reviewed-by: Brian King <redacted>
---
drivers/scsi/cxlflash/superpipe.c | 9 +++++++++
1 file changed, 9 insertions(+)
@@ -1787,12 +1787,21 @@ static int cxlflash_disk_verify(struct scsi_device *sdev,*inquiry(i.e.theUnitattentionisduetotheWWNchanging).*/if(verify->hint&DK_CXLFLASH_VERIFY_HINT_SENSE){+/* Can't hold mutex across process_sense/read_cap16,+*sincewecouldhaveaninterveningEEHevent.+*/+ctxi->unavail=true;+mutex_unlock(&ctxi->mutex);rc=process_sense(sdev,verify);if(unlikely(rc)){dev_err(dev,"%s: Failed to validate sense data (%d)\n",__func__,rc);+mutex_lock(&ctxi->mutex);+ctxi->unavail=false;gotoout;}+mutex_lock(&ctxi->mutex);+ctxi->unavail=false;}switch(gli->mode){
From: Matthew R. Ochs <hidden> Date: 2015-09-25 23:19:41
There are several spelling and grammar mistakes throughout the
driver. Additionally there are a handful of places where there
are extra lines and unnecessary variables/statements. These are
a nuisance and pollute the driver.
Fix spelling and grammar issues. Update some comments for clarity and
consistency. Remove extra lines and a few unneeded variables/statements.
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
Reviewed-by: Brian King <redacted>
---
drivers/scsi/cxlflash/common.h | 2 --
drivers/scsi/cxlflash/main.c | 62 +++++++++++++++++----------------------
drivers/scsi/cxlflash/sislite.h | 6 ++--
drivers/scsi/cxlflash/superpipe.c | 2 +-
drivers/scsi/cxlflash/vlun.c | 14 ++++-----
5 files changed, 38 insertions(+), 48 deletions(-)
@@ -34,7 +34,6 @@ MODULE_AUTHOR("Manoj N. Kumar <manoj@linux.vnet.ibm.com>");MODULE_AUTHOR("Matthew R. Ochs <mrochs@linux.vnet.ibm.com>");MODULE_LICENSE("GPL");-/***cmd_checkout()-checksoutanAFUcommand*@afu:AFUtocheckoutfrom.
@@ -730,7 +729,7 @@ static void cxlflash_remove(struct pci_dev *pdev)caseINIT_STATE_SCSI:cxlflash_term_local_luns(cfg);scsi_remove_host(cfg->host);-/* Fall through */+/* fall through */caseINIT_STATE_AFU:term_afu(cfg);cancel_work_sync(&cfg->work_q);
@@ -763,9 +762,7 @@ static int alloc_mem(struct cxlflash_cfg *cfg)char*buf=NULL;structdevice*dev=&cfg->dev->dev;-/* This allocation is about 12K, i.e. only 1 64k page-*andupto44kpages-*/+/* AFU is ~12k, i.e. only one 64k page or up to four 4k pages */cfg->afu=(void*)__get_free_pages(GFP_KERNEL|__GFP_ZERO,get_order(sizeof(structafu)));if(unlikely(!cfg->afu)){
@@ -1295,10 +1292,10 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data)gotoout;}-/* it is OK to clear AFU status before FC_ERROR */+/* FYI, it is 'okay' to clear AFU status before FC_ERROR */writeq_be(reg_unmasked,&global->regs.aintr_clear);-/* check each bit that is on */+/* Check each bit that is on */for(i=0;reg_unmasked;i++,reg_unmasked=(reg_unmasked>>1)){info=find_ainfo(1ULL<<i);if(((reg_unmasked&0x1)==0)||!info)
@@ -1472,23 +1469,22 @@ static void init_pcr(struct cxlflash_cfg *cfg)for(i=0;i<MAX_CONTEXT;i++){ctrl_map=&afu->afu_map->ctrls[i].ctrl;-/* disrupt any clients that could be running */-/* e. g. clients that survived a master restart */+/* Disrupt any clients that could be running */+/* e.g. clients that survived a master restart */writeq_be(0,&ctrl_map->rht_start);writeq_be(0,&ctrl_map->rht_cnt_id);writeq_be(0,&ctrl_map->ctx_cap);}-/* copy frequently used fields into afu */+/* Copy frequently used fields into afu */afu->ctx_hndl=(u16)cxl_process_element(cfg->mcctx);-/* ctx_hndl is 16 bits in CAIA */afu->host_map=&afu->afu_map->hosts[afu->ctx_hndl].host;afu->ctrl_map=&afu->afu_map->ctrls[afu->ctx_hndl].ctrl;/* Program the Endian Control for the master context */writeq_be(SISL_ENDIAN_CTRL,&afu->host_map->endian_ctrl);-/* initialize cmd fields that never change */+/* 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;
@@ -1517,7 +1513,7 @@ static int init_global(struct cxlflash_cfg *cfg)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 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);
@@ -1530,9 +1526,9 @@ static int init_global(struct cxlflash_cfg *cfg)/* checker on if dual afu */writeq_be(reg,&afu->afu_map->global.regs.afu_config);-/* global port select: select either port */+/* Global port select: select either port */if(afu->internal_lun){-/* only use port 0 */+/* Only use port 0 */writeq_be(PORT0,&afu->afu_map->global.regs.afu_port_sel);num_ports=NUM_FC_PORTS-1;}else{
@@ -1541,15 +1537,15 @@ static int init_global(struct cxlflash_cfg *cfg)}for(i=0;i<num_ports;i++){-/* unmask all errors (but they are still masked at AFU) */+/* Unmask all errors (but they are still masked at AFU) */writeq_be(0,&afu->afu_map->global.fc_regs[i][FC_ERRMSK/8]);-/* clear CRC error cnt & set a threshold */+/* 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]);-/* set WWPNs. If already programmed, wwpn[i] is 0 */+/* 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],
@@ -1563,18 +1559,17 @@ static int init_global(struct cxlflash_cfg *cfg)*offline/onlinetransitionsandaPLOGI*/msleep(100);-}-/* set up master's own CTX_CAP to allow real mode, host translation */-/* tbls, afu cmds and read/write GSCSI cmds. */+/* Set up master's own CTX_CAP to allow real mode, host translation */+/* tables, afu cmds and read/write GSCSI cmds. *//* First, unlock ctx_cap write by reading mbox */(void)readq_be(&afu->ctrl_map->mbox_r);/* unlock ctx_cap */writeq_be((SISL_CTX_CAP_REAL_MODE|SISL_CTX_CAP_HOST_XLATE|SISL_CTX_CAP_READ_CMD|SISL_CTX_CAP_WRITE_CMD|SISL_CTX_CAP_AFU_CMD|SISL_CTX_CAP_GSCSI_CMD),&afu->ctrl_map->ctx_cap);-/* init heartbeat */+/* Initialize heartbeat */afu->hb=readq_be(&afu->afu_map->global.regs.afu_hb);out:
@@ -1726,8 +1721,7 @@ static int init_afu(struct cxlflash_cfg *cfg)gotoerr1;}-/* Map the entire MMIO space of the AFU.-*/+/* Map the entire MMIO space of the AFU */afu->afu_map=cxl_psa_map(cfg->mcctx);if(!afu->afu_map){rc=-ENOMEM;
@@ -1845,7 +1839,7 @@ retry:wait_resp(afu,cmd);-/* set on timeout */+/* Set on timeout */if(unlikely((cmd->sa.ioasc!=0)||(cmd->sa.host_use_b[0]&B_ERROR)))rc=-1;
@@ -2262,7 +2256,7 @@ static struct scsi_host_template driver_template = {.cmd_per_lun=16,.can_queue=CXLFLASH_MAX_CMDS,.this_id=-1,-.sg_tablesize=SG_NONE,/* No scatter gather support. */+.sg_tablesize=SG_NONE,/* No scatter gather support */.max_sectors=CXLFLASH_MAX_SECTORS,.use_clustering=ENABLE_CLUSTERING,.shost_attrs=cxlflash_host_attrs,
@@ -2322,8 +2316,7 @@ static void cxlflash_worker_thread(struct work_struct *work)/* The reset can block... */afu_link_reset(afu,port,-&afu->afu_map->-global.fc_regs[port][0]);+&afu->afu_map->global.fc_regs[port][0]);spin_lock_irqsave(cfg->host->host_lock,lock_flags);}
@@ -2402,7 +2395,6 @@ static int cxlflash_probe(struct pci_dev *pdev,cfg->last_lun_index[1]=CXLFLASH_NUM_VLUNS/2-1;cfg->dev_id=(structpci_device_id*)dev_id;-cfg->mcctx=NULL;init_waitqueue_head(&cfg->tmf_waitq);init_waitqueue_head(&cfg->reset_waitq);
@@ -2418,7 +2410,8 @@ static int cxlflash_probe(struct pci_dev *pdev,pci_set_drvdata(pdev,cfg);-/* Use the special service provided to look up the physical+/*+*Usethespecialserviceprovidedtolookupthephysical*PCIdevice,sincewearecalledontheprobeofthevirtual*PCIhostbus(vphb)*/
@@ -2448,7 +2441,6 @@ static int cxlflash_probe(struct pci_dev *pdev,}cfg->init_state=INIT_STATE_AFU;-rc=init_scsi(cfg);if(rc){dev_err(&pdev->dev,"%s: call to init_scsi "
@@ -146,7 +146,7 @@ struct sisl_rc {#define SISL_FC_RC_ABORTFAIL 0x59 /* pending abort completed w/fail */#define SISL_FC_RC_RESID 0x5A /* ioasa underrun/overrun flags set */#define SISL_FC_RC_RESIDERR 0x5B /* actual data len does not match SCSI-reportedlen,possblyduetodropped+reportedlen,possiblyduetodroppedframes*/#define SISL_FC_RC_TGTABORT 0x5C /* command aborted by target */};
@@ -258,7 +258,7 @@ struct sisl_host_map {__be64rrq_start;/* start & end are both inclusive */__be64rrq_end;/* write sequence: start followed by end */__be64cmd_room;-__be64ctx_ctrl;/* least signiifcant byte or b56:63 is LISN# */+__be64ctx_ctrl;/* least significant byte or b56:63 is LISN# */__be64mbox_w;/* restricted use */};
@@ -132,7 +132,7 @@ static int ba_init(struct ba_lun *ba_lun)return-ENOMEM;}-/* Pass the allocated lun info as a handle to the user */+/* Pass the allocated LUN info as a handle to the user */ba_lun->ba_lun_handle=bali;pr_debug("%s: Successfully initialized the LUN: "
@@ -165,7 +165,7 @@ static int find_free_range(u32 low,num_bits=(sizeof(*lam)*BITS_PER_BYTE);bit_pos=find_first_bit(lam,num_bits);-pr_devel("%s: Found free bit %llX in lun "+pr_devel("%s: Found free bit %llX in LUN ""map entry %llX at bitmap index = %X\n",__func__,bit_pos,bali->lun_alloc_map[i],i);
From: Matthew R. Ochs <hidden> Date: 2015-09-25 23:19:47
Following an adapter reset, the AFU RRQ that resides in host memory
holds stale data. This can lead to a condition where the RRQ interrupt
handler tries to process stale entries and/or endlessly loops due to an
out of sync generation bit.
To fix, the AFU RRQ in host memory needs to be cleared after each reset.
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
Reviewed-by: Brian King <redacted>
---
drivers/scsi/cxlflash/main.c | 3 +++
1 file changed, 3 insertions(+)
@@ -1598,6 +1598,9 @@ static int start_afu(struct cxlflash_cfg *cfg)init_pcr(cfg);+/* After an AFU reset, RRQ entries are stale, clear them */+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];
From: Matthew R. Ochs <hidden> Date: 2015-09-25 23:19:55
Add stanza for cxlflash SCSI driver.
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
Reviewed-by: Brian King <redacted>
Reviewed-by: Andrew Donnellan <redacted>
---
MAINTAINERS | 9 +++++++++
1 file changed, 9 insertions(+)
From: Matthew R. Ochs <hidden> Date: 2015-09-25 23:19:55
Several function prologs have incorrect parameter names and return
code descriptions. This can lead to confusion when reviewing the
source and creates inaccurate documentation.
To remedy, update the function prologs to properly reflect parameter
names and return codes.
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
Reviewed-by: Brian King <redacted>
---
drivers/scsi/cxlflash/main.c | 68 ++++++++++++++++----------------------------
1 file changed, 25 insertions(+), 43 deletions(-)
From: Matthew R. Ochs <hidden> Date: 2015-09-25 23:20:01
From: Manoj Kumar <redacted>
The operator used to double the delay is incorrect and
does not result in delay doubling.
To fix, use a left shift instead of the XOR operator.
Reported-by: Tomas Henzl <redacted>
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
Reviewed-by: Brian King <redacted>
---
drivers/scsi/cxlflash/main.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
@@ -303,7 +303,7 @@ write_rrin:if(rrin!=0x1)break;/* Double delay each time */-udelay(2^nretry);+udelay(2<<nretry);}while(nretry++<MC_ROOM_RETRY_CNT);}
From: Matthew R. Ochs <hidden> Date: 2015-09-25 23:20:07
The fops owned by the adapter can be corrupted in certain scenarios,
opening a window where certain fops are temporarily NULLed before being
reset to their proper value. This can potentially lead software to make
incorrect decisions, leaving the user with the inability to function as
intended.
An example of this behavior can be observed when there are a number of
users with a high rate of turn around (attach to LUN, perform an I/O,
detach from LUN, repeat). Every so often a user is given a valid
context and adapter file descriptor, but the file associated with the
descriptor lacks the correct read permission bit (FMODE_CAN_READ) and
thus the read system call bails before calling the valid read fop.
Background:
The fops is stored in the adapter structure to provide the ability to
lookup the adapter structure from within the fop handler. CXL services
use the file's private_data and at present, the CXL context does not
have a private section. In an effort to limit areas of the cxlflash
driver with code specific the superpipe function, a design choice was
made to keep the details of the fops situated away from the legacy
portions of the driver. This drove the behavior that the adapter fops
is set at the beginning of the disk attach ioctl handler when there
are no users present.
The corruption that this fix remedies is due to the fact that the fops
is initially defaulted to values found within a static structure. When
the fops is handed down to the CXL services later in the attach path,
certain services are patched. The fops structure remains correct until
the user count drops to 0 and the fops is reset, triggering the process
to repeat again. The user counts are tightly coupled with the creation
and deletion of the user context. If multiple users perform a disk
attach at the same time, when the user count is currently 0, some users
can be in the middle of obtaining a file descriptor and have not yet
reached the context creation code that [in addition to creating the
context] increments the user count. Subsequent users coming in to
perform the attach see that the user count is still 0, and reinitialize
the fops, temporarily removing the patched fops. The users that are in
the middle obtaining their file descriptor may then receive an invalid
descriptor.
The fix simply removes the user count altogether and moves the fops
initialization to probe time such that it is only performed one time
for the life of the adapter. In the future, if the CXL services adopt
a private member for their context, that could be used to store the
adapter structure reference and cxlflash could revert to a model that
does not require an embedded fops.
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
---
drivers/scsi/cxlflash/common.h | 3 +--
drivers/scsi/cxlflash/main.c | 1 +
drivers/scsi/cxlflash/superpipe.c | 11 +----------
3 files changed, 3 insertions(+), 12 deletions(-)
@@ -1286,10 +1281,6 @@ static int cxlflash_disk_attach(struct scsi_device *sdev,intfd=-1;-/* On first attach set fileops */-if(atomic_read(&cfg->num_user_contexts)==0)-cfg->cxl_fops=cxlflash_cxl_fops;-if(attach->num_interrupts>4){dev_dbg(dev,"%s: Cannot support this many interrupts %llu\n",__func__,attach->num_interrupts);
From: Matthew R. Ochs <hidden> Date: 2015-09-25 23:21:05
The trace following the failure of alloc_mem() incorrectly identifies
which function failed. This can lead to misdiagnosing a failure.
Fix the string to correctly indicate that alloc_mem() failed.
Reported-by: Brian King <redacted>
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
Reviewed-by: Brian King <redacted>
---
drivers/scsi/cxlflash/main.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
From: Matthew R. Ochs <hidden> Date: 2015-09-25 23:21:39
Ioctl threads that use scsi_execute() can run for an excessive amount
of time due to the fact that they have lengthy timeouts and retry logic
built in. Under normal operation this is not an issue. However, once EEH
enters the picture, a long execution time coupled with the possibility
that a timeout can trigger entry to the driver via registered reset
callbacks becomes a liability.
In particular, a deadlock can occur when an EEH event is encountered
while in running in scsi_execute(). As part of the recovery, the EEH
handler drains all currently running ioctls, waiting until they have
completed before proceeding with a reset. As the scsi_execute()'s are
situated on the ioctl path, the EEH handler will wait until they (and
the remainder of the ioctl handler they're associated with) have
completed. Normally this would not be much of an issue aside from the
longer recovery period. Unfortunately, the scsi_execute() triggers a
reset when it times out. The reset handler will see that the device is
already being reset and wait until that reset completed. This creates
a condition where the EEH handler becomes stuck, infinitely waiting for
the ioctl thread to complete.
To avoid this behavior, temporarily unmark the scsi_execute() threads
as an ioctl thread by releasing the ioctl read semaphore. This allows
the EEH handler to proceed with a recovery while the thread is still
running. Once the scsi_execute() returns, the ioctl read semaphore is
reacquired and the adapter state is rechecked in case it changed while
inside of scsi_execute(). The state check will wait if the adapter is
still being recovered or returns a failure if the recovery failed. In
the event that the adapter reset failed, the failure is simply returned
as the ioctl would be unable to continue.
Reported-by: Brian King <redacted>
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
---
drivers/scsi/cxlflash/superpipe.c | 30 +++++++++++++++++++++++++++++-
drivers/scsi/cxlflash/superpipe.h | 2 ++
drivers/scsi/cxlflash/vlun.c | 29 +++++++++++++++++++++++++++++
3 files changed, 60 insertions(+), 1 deletion(-)
@@ -314,8 +332,18 @@ retry:dev_dbg(dev,"%s: %ssending cmd(0x%x)\n",__func__,retry_cnt?"re":"",scsi_cmd[0]);+/* Drop the ioctl read semahpore across lengthy call */+up_read(&cfg->ioctl_rwsem);result=scsi_execute(sdev,scsi_cmd,DMA_FROM_DEVICE,cmd_buf,CMD_BUFSIZE,sense_buf,to,CMD_RETRIES,0,NULL);+down_read(&cfg->ioctl_rwsem);+rc=check_state(cfg);+if(rc){+dev_err(dev,"%s: Failed state! result=0x08%X\n",+__func__,result);+rc=-ENODEV;+gotoout;+}if(driver_byte(result)==DRIVER_SENSE){result&=~(0xFF<<24);/* DRIVER_SENSE is not an error */
From: Daniel Axtens <hidden> Date: 2015-09-28 22:35:54
=2D----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512
Looks good to me.
Reviewed-by: Daniel Axtens <redacted>
Regards,
Daniel
"Matthew R. Ochs" [off-list ref] writes:
quoted hunk
Using sizeof(bool) is considered poor form for various reasons and
sparse warns us of that. Correct by changing type from bool to u8.
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
Reviewed-by: Brian King <redacted>
---
drivers/scsi/cxlflash/superpipe.c | 2 +-
drivers/scsi/cxlflash/superpipe.h | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
@@ -97,7 +97,7 @@ struct ctx_info {u32rht_out;/* Number of checked out RHT entries */u32rht_perms;/* User-defined permissions for RHT entries */structllun_info**rht_lun;/* Mapping of RHT entries to LUNs */-bool*rht_needs_ws;/* User-desired write-same function per RHTE */+u8*rht_needs_ws;/* User-desired write-same function per RHTE */
From: Daniel Axtens <hidden> Date: 2015-09-28 22:39:22
=2D----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512
Looks good to me.
Reviewed-by: Daniel Axtens <redacted>
Regards,
Daniel
"Matthew R. Ochs" [off-list ref] writes:
quoted hunk
The context encode mask covers more than 32-bits, making it
a long integer. This should be noted by appending the ULL
width suffix to the mask.
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
Reviewed-by: Brian King <redacted>
---
drivers/scsi/cxlflash/superpipe.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
From: Daniel Axtens <hidden> Date: 2015-09-28 23:05:18
You have two versions of check_state() below, which is a bit
confusing. It looks like you've moved the function and also added the
up/down of the read semaphore. I assume that's all that changed?
quoted hunk
/**
+ * check_state() - checks and responds to the current adapter state
+ * @cfg: Internal structure associated with the host.
+ *
+ * This routine can block and should only be used on process context.
+ * It assumes that the caller is an ioctl thread and holding the ioctl
+ * read semaphore. This is temporarily let up across the wait to allow
+ * for draining actively running ioctls. Also note that when waking up
+ * from waiting in reset, the state is unknown and must be checked again
+ * before proceeding.
+ *
+ * Return: 0 on success, -errno on failure
+ */
+static int check_state(struct cxlflash_cfg *cfg)
+{
+ struct device *dev = &cfg->dev->dev;
+ int rc = 0;
+
+retry:
+ switch (cfg->state) {
+ case STATE_LIMBO:
+ dev_dbg(dev, "%s: Limbo state, going to wait...\n", __func__);
+ up_read(&cfg->ioctl_rwsem);
+ rc = wait_event_interruptible(cfg->limbo_waitq,
+ cfg->state != STATE_LIMBO);
+ down_read(&cfg->ioctl_rwsem);
+ if (unlikely(rc))
+ break;
+ goto retry;
+ case STATE_FAILTERM:
+ dev_dbg(dev, "%s: Failed/Terminating!\n", __func__);
+ rc = -ENODEV;
+ break;
+ default:
+ break;
+ }
+
+ return rc;
+}
+
+/**
* cxlflash_disk_attach() - attach a LUN to a context
* @sdev: SCSI device associated with LUN.
* @attach: Attach ioctl data structure.
@@ -1523,41 +1563,6 @@ err1: } /**- * check_state() - checks and responds to the current adapter state- * @cfg: Internal structure associated with the host.- *- * This routine can block and should only be used on process context.- * Note that when waking up from waiting in limbo, the state is unknown- * and must be checked again before proceeding.- *- * Return: 0 on success, -errno on failure- */-static int check_state(struct cxlflash_cfg *cfg)-{- struct device *dev = &cfg->dev->dev;- int rc = 0;--retry:- switch (cfg->state) {- case STATE_LIMBO:- dev_dbg(dev, "%s: Limbo, going to wait...\n", __func__);- rc = wait_event_interruptible(cfg->limbo_waitq,- cfg->state != STATE_LIMBO);- if (unlikely(rc))- break;- goto retry;- case STATE_FAILTERM:- dev_dbg(dev, "%s: Failed/Terminating!\n", __func__);- rc = -ENODEV;- break;- default:- break;- }-- return rc;-}--/** * cxlflash_afu_recover() - initiates AFU recovery * @sdev: SCSI device associated with LUN. * @recover: Recover ioctl data structure.
@@ -1646,9 +1651,14 @@ retry_recover: /* Test if in error state */ reg = readq_be(&afu->ctrl_map->mbox_r); if (reg == -1) {- dev_dbg(dev, "%s: MMIO read fail! Wait for recovery...\n",- __func__);- mutex_unlock(&ctxi->mutex);+ dev_dbg(dev, "%s: MMIO fail, wait for recovery.\n", __func__);++ /*+ * Before checking the state, put back the context obtained with+ * get_context() as it is no longer needed and sleep for a short+ * period of time (see prolog notes).+ */+ put_context(ctxi);
Is this needed for the drain to work? It looks like it fixes a
refcounting bug in the function, but I'm not sure I understand how it
interacts with the rest of this patch.
Anyway, the patch overall looks good to me, and makes your driver
interact with CXL's EEH support in the way I intended when I wrote it.
Reviewed-by: Daniel Axtens <redacted>
Regards,
Daniel
From: Daniel Axtens <hidden> Date: 2015-09-28 23:09:19
=2D----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512
"Matthew R. Ochs" [off-list ref] writes:
Looks good from an EEH point of view: in an error situation, your driver
asks to be reset and then is waiting for CXL and EEH to carry that out,
so 'reset' matches with that as well.
Reviewed-by: Daniel Axtens <redacted>
quoted hunk
Limbo is not an accurate representation of this state and is
also not consistent with the terminology that other drivers
use to represent this concept. Rename the state and and its
associated waitq to 'reset'.
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
Reviewed-by: Brian King <redacted>
---
drivers/scsi/cxlflash/common.h | 4 ++--
drivers/scsi/cxlflash/main.c | 26 +++++++++++++-------------
drivers/scsi/cxlflash/superpipe.c | 14 +++++++-------
3 files changed, 22 insertions(+), 22 deletions(-)
=20=20
dev_dbg(dev, "%s: Wait for user contexts to quiesce...\n",
__func__);
- wake_up_all(&cfg->limbo_waitq);
+ wake_up_all(&cfg->reset_waitq);
ssleep(1);
}
}
@@ -1233,11 +1233,11 @@ static int check_state(struct cxlflash_cfg *cfg)
=20=20
retry:
switch (cfg->state) {
- case STATE_LIMBO:
- dev_dbg(dev, "%s: Limbo state, going to wait...\n", __func__);
+ case STATE_RESET:
+ dev_dbg(dev, "%s: Reset state, going to wait...\n", __func__);
up_read(&cfg->ioctl_rwsem);
- rc =3D wait_event_interruptible(cfg->limbo_waitq,
- cfg->state !=3D STATE_LIMBO);
+ rc =3D wait_event_interruptible(cfg->reset_waitq,
+ cfg->state !=3D STATE_RESET);
down_read(&cfg->ioctl_rwsem);
if (unlikely(rc))
break;
@@ -1578,10 +1578,10 @@ err1: * quite possible for this routine to act as the kernel's EEH detection * source (MMIO read of mbox_r). Because of this, there is a window of * time where an EEH might have been detected but not yet 'serviced'- * (callback invoked, causing the device to enter limbo state). To avoid+ * (callback invoked, causing the device to enter reset state). To avoid * looping in this routine during that window, a 1 second sleep is in pl=
ace
* between the time the MMIO failure is detected and the time a wait on =
the
- * limbo wait queue is attempted via check_state().
+ * reset wait queue is attempted via check_state().
*
* Return: 0 on success, -errno on failure
*/
--=20
2.1.0
From: Daniel Axtens <hidden> Date: 2015-09-28 23:37:45
=2D----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512
Hi,
static int afu_set_wwpn(struct afu *afu, int port, u64 *fc_regs, u64 wwp=
n)
{
- int ret =3D 0;
+ int rc =3D 0;
I realise it's nice to have things consistent, but making this change
now makes the rest of the patch quite difficult to follow.
quoted hunk
=20=20
set_port_offline(fc_regs);
=20=20
@@ -1038,33 +1038,26 @@ static int afu_set_wwpn(struct afu *afu, int port=
, u64 *fc_regs, u64 wwpn)
FC_PORT_STATUS_RETRY_CNT)) {
pr_debug("%s: wait on port %d to go offline timed out\n",
__func__, port);
- ret =3D -1; /* but continue on to leave the port back online */
+ rc =3D -1; /* but continue on to leave the port back online */
}
=20=20
- if (ret =3D=3D 0)
+ if (rc =3D=3D 0)
writeq_be(wwpn, &fc_regs[FC_PNAME / 8]);
=20=20
+ /* Always return success after programming WWPN */
+ rc =3D 0;
+
set_port_online(fc_regs);
=20=20
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);
- ret =3D -1;
-
- /*
- * Override for internal lun!!!
- */
- if (afu->internal_lun) {
- pr_debug("%s: Overriding port %d online timeout!!!\n",
- __func__, port);
- ret =3D 0;
- }
}
=20=20
- pr_debug("%s: returning rc=3D%d\n", __func__, ret);
+ pr_debug("%s: returning rc=3D%d\n", __func__, rc);
I'm not sure I fully understand the flow of this function, but it looks
like you set rc=3D0 regardless of how things actually go: is this ever
going to print a return value other than zero?
Regards,
Daniel
=2D----BEGIN PGP SIGNATURE-----
Version: GnuPG v1
Comment: GPGTools - https://gpgtools.org
iQIcBAEBCgAGBQJWCc87AAoJEPC3R3P2I92FQNcP/RF+M8MGZ2PJ8heh98D84rb5
Dx+Yq1czRJ+YZbK5tCfkyU66KspEzM7IIOiiXDLlBZ+AjcQtCUopTNMbL/UN+oVT
5lWrvPZlWRJqRN5bA/RA3i/DSBRucucmP8n4pmTKqsMMqKwzk/f3sE+Uo5oAzS+y
JaSywxm+Vd4dkW5T94kc6TXCeWcaD47tG0mgg0jHGwFtOioDEeWgf7Kie52+RV+o
I6z7GlQj9dgcKs2NmVr67AoY1dfRYl1ZvvJN7bYoLbHnEgiSw1d6XZK/2cqHzIpE
S1KEHOyuSZJh8Txwfg6oJ3sbpFZaurSIXDXfOhWuJ90OrOu4hgeODTPX/3o2CKae
K+WhsL6XOhrxyMhfq/VWplF6Hjo7VqLcT9e0sYZ4YNkUJrGAza3iPOqngK9zmdsM
80HLJdbsiZMkl+i55IOuisckCtvjUtVE+bDlzau6vwgBlgZ9DKByPPmqJGjS9I3L
vCEKsRZryaSvaYSnK46kpqXsukN/+QMefXL25IfTf4wQQaV4O+mSJxkkLXPAKqfd
cvCFg08MyAQS+YyNMBdFDJyj7tWVclGZhJkqlyjPjQ2YrFA5tQ7MoqY05NomxY9Q
xo0JuaceNccFetKPg1LMmTp5Ag/2DCcnGq/0Z3ioGVJTFIVil0BnWIFctlGbquya
n4Ylfe3h1T6hWJ7bjxwF
=3DcZRI
=2D----END PGP SIGNATURE-----
From: Brian King <hidden> Date: 2015-09-28 23:41:55
On 09/25/2015 06:19 PM, Matthew R. Ochs wrote:
quoted hunk
static int write_same16(struct scsi_device *sdev,
@@ -433,9 +451,20 @@ static int write_same16(struct scsi_device *sdev, put_unaligned_be32(ws_limit < left ? ws_limit : left, &scsi_cmd[10]);+ /* Drop the ioctl read semahpore across lengthy call */+ up_read(&cfg->ioctl_rwsem); result = scsi_execute(sdev, scsi_cmd, DMA_TO_DEVICE, cmd_buf, CMD_BUFSIZE, sense_buf, to, CMD_RETRIES, 0, NULL);+ down_read(&cfg->ioctl_rwsem);+ rc = check_state(cfg);+ if (rc) {+ dev_err(dev, "%s: Failed state! result=0x08%X\n",+ __func__, result);+ rc = -ENODEV;
Since check_state only returns 0 or -ENODEV, this is a bit redundant, but not worth redoing the
patch in my mind.
Reviewed-by: Brian King <redacted>
--
Brian King
Power Linux I/O
IBM Linux Technology Center
From: Andrew Donnellan <hidden> Date: 2015-09-29 00:54:56
On 26/09/15 09:19, Matthew R. Ochs wrote:
The fops owned by the adapter can be corrupted in certain scenarios,
opening a window where certain fops are temporarily NULLed before being
reset to their proper value. This can potentially lead software to make
incorrect decisions, leaving the user with the inability to function as
intended.
An example of this behavior can be observed when there are a number of
users with a high rate of turn around (attach to LUN, perform an I/O,
detach from LUN, repeat). Every so often a user is given a valid
context and adapter file descriptor, but the file associated with the
descriptor lacks the correct read permission bit (FMODE_CAN_READ) and
thus the read system call bails before calling the valid read fop.
Background:
The fops is stored in the adapter structure to provide the ability to
lookup the adapter structure from within the fop handler. CXL services
use the file's private_data and at present, the CXL context does not
have a private section. In an effort to limit areas of the cxlflash
driver with code specific the superpipe function, a design choice was
made to keep the details of the fops situated away from the legacy
portions of the driver. This drove the behavior that the adapter fops
is set at the beginning of the disk attach ioctl handler when there
are no users present.
The corruption that this fix remedies is due to the fact that the fops
is initially defaulted to values found within a static structure. When
the fops is handed down to the CXL services later in the attach path,
certain services are patched. The fops structure remains correct until
the user count drops to 0 and the fops is reset, triggering the process
to repeat again. The user counts are tightly coupled with the creation
and deletion of the user context. If multiple users perform a disk
attach at the same time, when the user count is currently 0, some users
can be in the middle of obtaining a file descriptor and have not yet
reached the context creation code that [in addition to creating the
context] increments the user count. Subsequent users coming in to
perform the attach see that the user count is still 0, and reinitialize
the fops, temporarily removing the patched fops. The users that are in
the middle obtaining their file descriptor may then receive an invalid
descriptor.
The fix simply removes the user count altogether and moves the fops
initialization to probe time such that it is only performed one time
for the life of the adapter. In the future, if the CXL services adopt
a private member for their context, that could be used to store the
adapter structure reference and cxlflash could revert to a model that
does not require an embedded fops.
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
Reviewed-by: Andrew Donnellan <redacted>
--
Andrew Donnellan Software Engineer, OzLabs
andrew.donnellan@au1.ibm.com Australia Development Lab, Canberra
+61 2 6201 8874 (work) IBM Australia Limited
From: Andrew Donnellan <hidden> Date: 2015-09-29 01:18:45
On 26/09/15 09:18, Matthew R. Ochs wrote:
There are several spelling and grammar mistakes throughout the
driver. Additionally there are a handful of places where there
are extra lines and unnecessary variables/statements. These are
a nuisance and pollute the driver.
Fix spelling and grammar issues. Update some comments for clarity and
consistency. Remove extra lines and a few unneeded variables/statements.
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
Reviewed-by: Brian King <redacted>
Reviewed-by: Andrew Donnellan <redacted>
--
Andrew Donnellan Software Engineer, OzLabs
andrew.donnellan@au1.ibm.com Australia Development Lab, Canberra
+61 2 6201 8874 (work) IBM Australia Limited
From: Andrew Donnellan <hidden> Date: 2015-09-29 01:19:42
On 26/09/15 09:19, Matthew R. Ochs wrote:
From: Manoj Kumar <redacted>
The operator used to double the delay is incorrect and
does not result in delay doubling.
To fix, use a left shift instead of the XOR operator.
Reported-by: Tomas Henzl <redacted>
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
Reviewed-by: Brian King <redacted>
Reviewed-by: Andrew Donnellan <redacted>
--
Andrew Donnellan Software Engineer, OzLabs
andrew.donnellan@au1.ibm.com Australia Development Lab, Canberra
+61 2 6201 8874 (work) IBM Australia Limited
From: Andrew Donnellan <hidden> Date: 2015-09-29 01:21:11
On 26/09/15 09:19, Matthew R. Ochs wrote:
The trace following the failure of alloc_mem() incorrectly identifies
which function failed. This can lead to misdiagnosing a failure.
Fix the string to correctly indicate that alloc_mem() failed.
Reported-by: Brian King <redacted>
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
Reviewed-by: Brian King <redacted>
Reviewed-by: Andrew Donnellan <redacted>
--
Andrew Donnellan Software Engineer, OzLabs
andrew.donnellan@au1.ibm.com Australia Development Lab, Canberra
+61 2 6201 8874 (work) IBM Australia Limited
From: Daniel Axtens <hidden> Date: 2015-09-29 01:26:09
=2D----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512
"Matthew R. Ochs" [off-list ref] writes:
The process_sense() routine can perform a read capacity which
can take some time to complete. If an EEH occurs while waiting
on the read capacity, the EEH handler is unable to obtain the
context's mutex in order to put the context in an error state.
The EEH handler will sit and wait until the context is free,
but this wait can last longer than the EEH handler tolerates,
leading to a failed recovery.
I'm not quite clear on what you mean by the EEH handler timing
out. AFAIK there's nothing in eehd and the EEH core that times out if a
driver doesn't respond - indeed, it's pretty easy to hang eehd with a
misbehaving driver.
Are you referring to your own internal timeouts?
cxlflash_wait_for_pci_err_recovery and anything else that uses
CXLFLASH_PCI_ERROR_RECOVERY_TIMEOUT?
Regards,
Daniel
quoted hunk
To address this issue, make the context unavailable to new,
non-system owned threads and release the context while calling
into process_sense(). After returning from process_sense() the
context mutex is reacquired and the context is made available
again. The context can be safely moved to the error state if
needed during the unavailable window as no other threads will
hold its reference.
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
Reviewed-by: Brian King <redacted>
---
drivers/scsi/cxlflash/superpipe.c | 9 +++++++++
1 file changed, 9 insertions(+)
@@ -1787,12 +1787,21 @@ static int cxlflash_disk_verify(struct scsi_devic=
e *sdev,
* inquiry (i.e. the Unit attention is due to the WWN changing).
*/
if (verify->hint & DK_CXLFLASH_VERIFY_HINT_SENSE) {
+ /* Can't hold mutex across process_sense/read_cap16,
+ * since we could have an intervening EEH event.
+ */
+ ctxi->unavail =3D true;
+ mutex_unlock(&ctxi->mutex);
rc =3D process_sense(sdev, verify);
if (unlikely(rc)) {
dev_err(dev, "%s: Failed to validate sense data (%d)\n",
__func__, rc);
+ mutex_lock(&ctxi->mutex);
+ ctxi->unavail =3D false;
goto out;
}
+ mutex_lock(&ctxi->mutex);
+ ctxi->unavail =3D false;
}
=20=20
switch (gli->mode) {
--=20
2.1.0
From: Daniel Axtens <hidden> Date: 2015-09-29 01:36:46
=2D----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512
"Matthew R. Ochs" [off-list ref] writes:
Following an adapter reset, the AFU RRQ that resides in host memory
holds stale data. This can lead to a condition where the RRQ interrupt
handler tries to process stale entries and/or endlessly loops due to an
out of sync generation bit.
To fix, the AFU RRQ in host memory needs to be cleared after each reset.
This looks good. Do you need anything to bail out of cxlflash_rrq_irq if
the data goes stale or to all Fs while that function is running?
Daniel
quoted hunk
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
Reviewed-by: Brian King <redacted>
---
drivers/scsi/cxlflash/main.c | 3 +++
1 file changed, 3 insertions(+)
From: Daniel Axtens <hidden> Date: 2015-09-29 01:40:46
=2D----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512
"Matthew R. Ochs" [off-list ref] writes:
From: Manoj Kumar <redacted>
The operator used to double the delay is incorrect and
does not result in delay doubling.
To fix, use a left shift instead of the XOR operator.
I can see that the patch is correct, but this commit message is a bit
confusing. What delay? In what circumstances are you doubling it? Why?
Regards,
Daniel
quoted hunk
Reported-by: Tomas Henzl <redacted>
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
Reviewed-by: Brian King <redacted>
---
drivers/scsi/cxlflash/main.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
@@ -303,7 +303,7 @@ write_rrin:if(rrin!=3D0x1)break;/* Double delay each time */-udelay(2^nretry);+udelay(2<<nretry);}while(nretry++<MC_ROOM_RETRY_CNT);}
From: Andrew Donnellan <hidden> Date: 2015-09-29 01:52:46
On 26/09/15 09:18, Matthew R. Ochs wrote:
Sparse uncovered several errors with MMIO operations (accessing
directly) and handling endianness. These can cause issues when
running in different environments.
Introduce __iomem and proper endianness tags/swaps where
appropriate to make driver sparse clean.
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
Reviewed-by: Brian King <redacted>
Reviewed-by: Andrew Donnellan <redacted>
--
Andrew Donnellan Software Engineer, OzLabs
andrew.donnellan@au1.ibm.com Australia Development Lab, Canberra
+61 2 6201 8874 (work) IBM Australia Limited
From: Andrew Donnellan <hidden> Date: 2015-09-29 04:29:48
On 26/09/15 09:14, Matthew R. Ochs wrote:
Implement the following suggestions and add two new attributes
to allow for debugging the port LUN table.
- use scnprintf() instead of snprintf()
- use DEVICE_ATTR_RO and DEVICE_ATTR_RW
Suggested-by: Shane Seymour <redacted>
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
Reviewed-by: Brian King <redacted>
The commit message could explain the patch a bit better.
Andrew
--
Andrew Donnellan Software Engineer, OzLabs
andrew.donnellan@au1.ibm.com Australia Development Lab, Canberra
+61 2 6201 8874 (work) IBM Australia Limited
From: Andrew Donnellan <hidden> Date: 2015-09-29 04:36:49
On 26/09/15 09:18, Matthew R. Ochs wrote:
Several function prologs have incorrect parameter names and return
code descriptions. This can lead to confusion when reviewing the
source and creates inaccurate documentation.
To remedy, update the function prologs to properly reflect parameter
names and return codes.
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
Reviewed-by: Brian King <redacted>
Reviewed-by: Andrew Donnellan <redacted>
See further comments below.
I'd prefer it to say "SCSI_MLQUEUE_HOST_BUSY on failure". (Aesthetically
I prefer having it on a separate line, but that's just personal preference.)
As an aside, while checking the correctness of this, I found that the
comment for cxlflash_send_cmd() states that it returns -1 on failure,
when the only error value it actually returns is SCSI_MLQUEUE_HOST_BUSY.
If you send a v5 you might want to fix this.
Andrew
--
Andrew Donnellan Software Engineer, OzLabs
andrew.donnellan@au1.ibm.com Australia Development Lab, Canberra
+61 2 6201 8874 (work) IBM Australia Limited
From: Andrew Donnellan <hidden> Date: 2015-09-29 05:06:36
On 26/09/15 09:15, Matthew R. Ochs wrote:
During run-time the driver can be very chatty and spam the system
kernel log. Various print statements can be limited and/or moved
to development-only mode. Additionally, numerous prints can be
converted to trace the corresponding device.
The following changes were made:
- pr_debug to pr_devel
- pr_debug to pr_debug_ratelimited
- pr_err to dev_err
- pr_debug to dev_dbg
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
Reviewed-by: Brian King <redacted>
Reviewed-by: Andrew Donnellan <redacted>
Changes mostly look fine, further comments below.
Why has the message changed from scsi_set_resid to scsi_done, and should
the message be moved to immediately before the scsi_done call?
Andrew
--
Andrew Donnellan Software Engineer, OzLabs
andrew.donnellan@au1.ibm.com Australia Development Lab, Canberra
+61 2 6201 8874 (work) IBM Australia Limited
From: Andrew Donnellan <hidden> Date: 2015-09-29 05:41:39
On 26/09/15 09:12, Matthew R. Ochs wrote:
From: Manoj Kumar <redacted>
Magic numbers are not meaningful and can create confusion. As a
remedy, replace them with descriptive literals.
Replace 512 with literal MAX_SECTOR_UNIT.
Replace 5 with literal CMD_RETRIES.
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
Reviewed-by: Brian King <redacted>
Reviewed-by: Andrew Donnellan <redacted>
--
Andrew Donnellan Software Engineer, OzLabs
andrew.donnellan@au1.ibm.com Australia Development Lab, Canberra
+61 2 6201 8874 (work) IBM Australia Limited
From: Matthew R. Ochs <hidden> Date: 2015-09-29 19:33:09
On Sep 28, 2015, at 6:05 PM, Daniel Axtens [off-list ref] wrote:
=20
You have two versions of check_state() below, which is a bit
confusing. It looks like you've moved the function and also added the
up/down of the read semaphore. I assume that's all that changed?
Correct.
It was originally moved to meet a dependency due to it being defined =
statically.
=20
quoted
=20
/**
+ * check_state() - checks and responds to the current adapter state
+ * @cfg: Internal structure associated with the host.
+ *
+ * This routine can block and should only be used on process =
context.
quoted
+ * It assumes that the caller is an ioctl thread and holding the =
ioctl
quoted
+ * read semaphore. This is temporarily let up across the wait to =
allow
quoted
+ * for draining actively running ioctls. Also note that when waking =
up
quoted
+ * from waiting in reset, the state is unknown and must be checked =
again
quoted
+ * before proceeding.
+ *
+ * Return: 0 on success, -errno on failure
+ */
+static int check_state(struct cxlflash_cfg *cfg)
+{
+ struct device *dev =3D &cfg->dev->dev;
+ int rc =3D 0;
+
+retry:
+ switch (cfg->state) {
+ case STATE_LIMBO:
+ dev_dbg(dev, "%s: Limbo state, going to wait...\n", =
+ down_read(&cfg->ioctl_rwsem);
+ if (unlikely(rc))
+ break;
+ goto retry;
+ case STATE_FAILTERM:
+ dev_dbg(dev, "%s: Failed/Terminating!\n", __func__);
+ rc =3D -ENODEV;
+ break;
+ default:
+ break;
+ }
+
+ return rc;
+}
+
+/**
* cxlflash_disk_attach() - attach a LUN to a context
* @sdev: SCSI device associated with LUN.
* @attach: Attach ioctl data structure.
@@ -1523,41 +1563,6 @@ err1:
}
=20
/**
- * check_state() - checks and responds to the current adapter state
- * @cfg: Internal structure associated with the host.
- *
- * This routine can block and should only be used on process =
context.
quoted
- * Note that when waking up from waiting in limbo, the state is =
unknown
quoted
- * and must be checked again before proceeding.
- *
- * Return: 0 on success, -errno on failure
- */
-static int check_state(struct cxlflash_cfg *cfg)
-{
- struct device *dev =3D &cfg->dev->dev;
- int rc =3D 0;
-
-retry:
- switch (cfg->state) {
- case STATE_LIMBO:
- dev_dbg(dev, "%s: Limbo, going to wait...\n", __func__);
- rc =3D wait_event_interruptible(cfg->limbo_waitq,
- cfg->state !=3D =
+
+ /*
+ * Before checking the state, put back the context =
obtained with
quoted
+ * get_context() as it is no longer needed and sleep for =
a short
quoted
+ * period of time (see prolog notes).
+ */
+ put_context(ctxi);
=20
Is this needed for the drain to work? It looks like it fixes a
refcounting bug in the function, but I'm not sure I understand how it
interacts with the rest of this patch.
This was simply some "while I'm here" refactoring as the commit =
originally
included a change here. The main point of this change was to replace the
mutex_unlock() with put_context(), which is a wrapper around the =
unlocking
of the context's mutex.
=20
Anyway, the patch overall looks good to me, and makes your driver
interact with CXL's EEH support in the way I intended when I wrote it.
I'm not sure I fully understand the flow of this function, but it =
looks
like you set rc=3D0 regardless of how things actually go: is this ever
going to print a return value other than zero?
Correct, this function behaves more like a void for the time being. The
overall goal of this is to allow a card to configure even when the link =
is
down. At some later point when the link is transitioned to 'up', a link =
state
change interrupt will trigger the port configuration. I left this with a =
return
code for right now in case we need to alter the behavior again (based
upon testing) and actually return a value other than 0.
=20
Since check_state only returns 0 or -ENODEV, this is a bit redundant, =
but not worth redoing the
patch in my mind.
Agreed. This occurred to me the other day after submitting this patch =
when I was
reviewing the state locking code. Will look at revising in a future =
patch.
Thanks again for reviewing.
From: Matthew R. Ochs <hidden> Date: 2015-09-29 20:11:22
On Sep 28, 2015, at 8:25 PM, Daniel Axtens [off-list ref] wrote:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512
"Matthew R. Ochs" [off-list ref] writes:
quoted
The process_sense() routine can perform a read capacity which
can take some time to complete. If an EEH occurs while waiting
on the read capacity, the EEH handler is unable to obtain the
context's mutex in order to put the context in an error state.
The EEH handler will sit and wait until the context is free,
but this wait can last longer than the EEH handler tolerates,
leading to a failed recovery.
I'm not quite clear on what you mean by the EEH handler timing
out. AFAIK there's nothing in eehd and the EEH core that times out if a
driver doesn't respond - indeed, it's pretty easy to hang eehd with a
misbehaving driver.
Are you referring to your own internal timeouts?
cxlflash_wait_for_pci_err_recovery and anything else that uses
CXLFLASH_PCI_ERROR_RECOVERY_TIMEOUT?
Reading through this again I can see how this is misleading. This is
actually similar and related to the deadlock scenario described in
"Fix to avoid potential deadlock on EEH". Without this fix, you'd end
up in a similar situation but deadlocked on the context mutex instead
of the ioctl semaphore.
From: Matthew R. Ochs <hidden> Date: 2015-09-29 20:22:39
On Sep 28, 2015, at 8:36 PM, Daniel Axtens [off-list ref] wrote:
=20
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512
=20
"Matthew R. Ochs" [off-list ref] writes:
=20
quoted
Following an adapter reset, the AFU RRQ that resides in host memory
holds stale data. This can lead to a condition where the RRQ =
interrupt
quoted
handler tries to process stale entries and/or endlessly loops due to =
an
quoted
out of sync generation bit.
=20
To fix, the AFU RRQ in host memory needs to be cleared after each =
reset.
=20
This looks good. Do you need anything to bail out of cxlflash_rrq_irq =
if
the data goes stale or to all Fs while that function is running?
We're not performing an MMIO here, so I'm not sure how the all Fs check
would apply. We're also protected fairly well by the generation bit. I =
suppose
we could look at adding some type of 'max iterations' count to protect =
against
a runaway handler but that would be in a future patch.
From: Matthew R. Ochs <hidden> Date: 2015-09-29 20:33:48
On Sep 28, 2015, at 8:40 PM, Daniel Axtens [off-list ref] wrote:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512
"Matthew R. Ochs" [off-list ref] writes:
quoted
From: Manoj Kumar <redacted>
The operator used to double the delay is incorrect and
does not result in delay doubling.
To fix, use a left shift instead of the XOR operator.
I can see that the patch is correct, but this commit message is a bit
confusing. What delay? In what circumstances are you doubling it? Why?
This is the response delay while resetting the master context. The reset
is performed by writing a bit and then waiting for it to clear. While waiting
for it to clear, the code relaxes the delta between MMIO reads.
* @host: SCSI host associated with device.
* @scp: SCSI command to send.
*
- * Return:
- * 0 on success
- * SCSI_MLQUEUE_HOST_BUSY when host is busy
+ * Return: 0 on success or SCSI_MLQUEUE_HOST_BUSY
*/
=20
I'd prefer it to say "SCSI_MLQUEUE_HOST_BUSY on failure". =
(Aesthetically I prefer having it on a separate line, but that's just =
personal preference.)
=20
As an aside, while checking the correctness of this, I found that the =
comment for cxlflash_send_cmd() states that it returns -1 on failure, =
when the only error value it actually returns is SCSI_MLQUEUE_HOST_BUSY. =
If you send a v5 you might want to fix this.
I'll make a note of this.
From: Matthew R. Ochs <hidden> Date: 2015-09-29 20:39:52
On Sep 29, 2015, at 12:05 AM, Andrew Donnellan =
[off-list ref] wrote:
On 26/09/15 09:15, Matthew R. Ochs wrote:
quoted
During run-time the driver can be very chatty and spam the system
kernel log. Various print statements can be limited and/or moved
to development-only mode. Additionally, numerous prints can be
converted to trace the corresponding device.
=20
The following changes were made:
- pr_debug to pr_devel
- pr_debug to pr_debug_ratelimited
- pr_err to dev_err
- pr_debug to dev_dbg
=20
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
Reviewed-by: Brian King <redacted>
=20
Reviewed-by: Andrew Donnellan <redacted>
=20
Changes mostly look fine, further comments below.
=20
From: Daniel Axtens <hidden> Date: 2015-09-30 00:08:31
"Matthew R. Ochs" [off-list ref] writes:
quoted
On Sep 28, 2015, at 8:40 PM, Daniel Axtens [off-list ref] wrote:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512
"Matthew R. Ochs" [off-list ref] writes:
quoted
From: Manoj Kumar <redacted>
The operator used to double the delay is incorrect and
does not result in delay doubling.
To fix, use a left shift instead of the XOR operator.
I can see that the patch is correct, but this commit message is a bit
confusing. What delay? In what circumstances are you doubling it? Why?
This is the response delay while resetting the master context. The reset
is performed by writing a bit and then waiting for it to clear. While waiting
for it to clear, the code relaxes the delta between MMIO reads.
OK. If you do a v5, please include this in the commit message.
Regards,
Daniel
From: Daniel Axtens <hidden> Date: 2015-09-30 00:18:19
"Matthew R. Ochs" [off-list ref] writes:
The corruption that this fix remedies is due to the fact that the fops
is initially defaulted to values found within a static structure. When
the fops is handed down to the CXL services later in the attach path,
certain services are patched. The fops structure remains correct until
the user count drops to 0 and the fops is reset, triggering the process
to repeat again. The user counts are tightly coupled with the creation
and deletion of the user context. If multiple users perform a disk
attach at the same time, when the user count is currently 0, some users
can be in the middle of obtaining a file descriptor and have not yet
reached the context creation code that [in addition to creating the
context] increments the user count. Subsequent users coming in to
perform the attach see that the user count is still 0, and reinitialize
the fops, temporarily removing the patched fops. The users that are in
the middle obtaining their file descriptor may then receive an invalid
descriptor.
The fix simply removes the user count altogether and moves the fops
initialization to probe time such that it is only performed one time
for the life of the adapter. In the future, if the CXL services adopt
a private member for their context, that could be used to store the
adapter structure reference and cxlflash could revert to a model that
does not require an embedded fops.
Yep, this looks good.
We have discussed adding a private data field to a cxl context, and will
no doubt revisit the question at some point in the future :)
Reviewed-by: Daniel Axtens <redacted>
quoted hunk
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
---
drivers/scsi/cxlflash/common.h | 3 +--
drivers/scsi/cxlflash/main.c | 1 +
drivers/scsi/cxlflash/superpipe.c | 11 +----------
3 files changed, 3 insertions(+), 12 deletions(-)
@@ -1286,10 +1281,6 @@ static int cxlflash_disk_attach(struct scsi_device *sdev,intfd=-1;-/* On first attach set fileops */-if(atomic_read(&cfg->num_user_contexts)==0)-cfg->cxl_fops=cxlflash_cxl_fops;-if(attach->num_interrupts>4){dev_dbg(dev,"%s: Cannot support this many interrupts %llu\n",__func__,attach->num_interrupts);
From: Daniel Axtens <hidden> Date: 2015-09-30 00:33:33
"Matthew R. Ochs" [off-list ref] writes:
Ioctl threads that use scsi_execute() can run for an excessive amount
of time due to the fact that they have lengthy timeouts and retry logic
built in. Under normal operation this is not an issue. However, once EEH
enters the picture, a long execution time coupled with the possibility
that a timeout can trigger entry to the driver via registered reset
callbacks becomes a liability.
In particular, a deadlock can occur when an EEH event is encountered
while in running in scsi_execute(). As part of the recovery, the EEH
handler drains all currently running ioctls, waiting until they have
completed before proceeding with a reset. As the scsi_execute()'s are
situated on the ioctl path, the EEH handler will wait until they (and
the remainder of the ioctl handler they're associated with) have
completed. Normally this would not be much of an issue aside from the
longer recovery period. Unfortunately, the scsi_execute() triggers a
reset when it times out. The reset handler will see that the device is
already being reset and wait until that reset completed. This creates
a condition where the EEH handler becomes stuck, infinitely waiting for
the ioctl thread to complete.
To avoid this behavior, temporarily unmark the scsi_execute() threads
as an ioctl thread by releasing the ioctl read semaphore. This allows
the EEH handler to proceed with a recovery while the thread is still
running. Once the scsi_execute() returns, the ioctl read semaphore is
reacquired and the adapter state is rechecked in case it changed while
inside of scsi_execute(). The state check will wait if the adapter is
still being recovered or returns a failure if the recovery failed. In
the event that the adapter reset failed, the failure is simply returned
as the ioctl would be unable to continue.
Yep, looks good.
Reviewed-by: Daniel Axtens <redacted>
quoted hunk
Reported-by: Brian King <redacted>
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
---
drivers/scsi/cxlflash/superpipe.c | 30 +++++++++++++++++++++++++++++-
drivers/scsi/cxlflash/superpipe.h | 2 ++
drivers/scsi/cxlflash/vlun.c | 29 +++++++++++++++++++++++++++++
3 files changed, 60 insertions(+), 1 deletion(-)
@@ -314,8 +332,18 @@ retry:dev_dbg(dev,"%s: %ssending cmd(0x%x)\n",__func__,retry_cnt?"re":"",scsi_cmd[0]);+/* Drop the ioctl read semahpore across lengthy call */+up_read(&cfg->ioctl_rwsem);result=scsi_execute(sdev,scsi_cmd,DMA_FROM_DEVICE,cmd_buf,CMD_BUFSIZE,sense_buf,to,CMD_RETRIES,0,NULL);+down_read(&cfg->ioctl_rwsem);+rc=check_state(cfg);+if(rc){+dev_err(dev,"%s: Failed state! result=0x08%X\n",+__func__,result);+rc=-ENODEV;+gotoout;+}if(driver_byte(result)==DRIVER_SENSE){result&=~(0xFF<<24);/* DRIVER_SENSE is not an error */
From: Daniel Axtens <hidden> Date: 2015-09-30 23:50:07
(resending to the list this time, apologies!)
quoted
I'm not sure I fully understand the flow of this function, but it looks
like you set rc=0 regardless of how things actually go: is this ever
going to print a return value other than zero?
Correct, this function behaves more like a void for the time being. The
overall goal of this is to allow a card to configure even when the link is
down. At some later point when the link is transitioned to 'up', a link state
change interrupt will trigger the port configuration. I left this with a return
code for right now in case we need to alter the behavior again (based
upon testing) and actually return a value other than 0.
OK. That makes more sense - it wasn't clear to me how it could be
correct to proceed if the links were down but now I understand how that
works. I think that explanation should go in the commit message.
quoted
quoted
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);
As an aside, should this be a bit noisier? It seems like something
a user would probably want to know - especially in the case where
something has actually gone wrong so there's no link state change
interrupt forthcoming regardless of how long you wait.
Regards,
Daniel
From: Daniel Axtens <hidden> Date: 2015-09-30 23:51:32
quoted
quoted
Following an adapter reset, the AFU RRQ that resides in host memory
holds stale data. This can lead to a condition where the RRQ interrupt
handler tries to process stale entries and/or endlessly loops due to an
out of sync generation bit.
To fix, the AFU RRQ in host memory needs to be cleared after each reset.
This looks good. Do you need anything to bail out of cxlflash_rrq_irq if
the data goes stale or to all Fs while that function is running?
We're not performing an MMIO here, so I'm not sure how the all Fs check
would apply. We're also protected fairly well by the generation bit. I suppose
we could look at adding some type of 'max iterations' count to protect against
a runaway handler but that would be in a future patch.
Ah, right you are. I had confused all Fs with UEs.
Reviewed-by: Daniel Axtens <redacted>
Regards,
Daniel
From: Daniel Axtens <hidden> Date: 2015-09-30 23:53:12
"Matthew R. Ochs" [off-list ref] writes:
quoted
quoted
The process_sense() routine can perform a read capacity which
can take some time to complete. If an EEH occurs while waiting
on the read capacity, the EEH handler is unable to obtain the
context's mutex in order to put the context in an error state.
The EEH handler will sit and wait until the context is free,
but this wait can last longer than the EEH handler tolerates,
leading to a failed recovery.
I'm not quite clear on what you mean by the EEH handler timing
out. AFAIK there's nothing in eehd and the EEH core that times out if a
driver doesn't respond - indeed, it's pretty easy to hang eehd with a
misbehaving driver.
Are you referring to your own internal timeouts?
cxlflash_wait_for_pci_err_recovery and anything else that uses
CXLFLASH_PCI_ERROR_RECOVERY_TIMEOUT?
Reading through this again I can see how this is misleading. This is
actually similar and related to the deadlock scenario described in
"Fix to avoid potential deadlock on EEH". Without this fix, you'd end
up in a similar situation but deadlocked on the context mutex instead
of the ioctl semaphore.
That makes _much_ more sense. If you could please revise the commit
message to explain that, you can include this in the next version:
Reviewed-by: Daniel Axtens <redacted>
Regards,
Daniel
From: Matthew R. Ochs <hidden> Date: 2015-10-01 15:00:34
On Sep 30, 2015, at 6:50 PM, Daniel Axtens [off-list ref] wrote:
(resending to the list this time, apologies!)
=20
quoted
quoted
I'm not sure I fully understand the flow of this function, but it =
looks
quoted
quoted
like you set rc=3D0 regardless of how things actually go: is this =
ever
quoted
quoted
going to print a return value other than zero?
=20
Correct, this function behaves more like a void for the time being. =
The
quoted
overall goal of this is to allow a card to configure even when the =
link is
quoted
down. At some later point when the link is transitioned to 'up', a =
link state
quoted
change interrupt will trigger the port configuration. I left this =
with a return
quoted
code for right now in case we need to alter the behavior again (based
upon testing) and actually return a value other than 0.
=20
OK. That makes more sense - it wasn't clear to me how it could be
correct to proceed if the links were down but now I understand how =
that
works. I think that explanation should go in the commit message.
=20
quoted
quoted
quoted
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);
=20
As an aside, should this be a bit noisier? It seems like something
a user would probably want to know - especially in the case where
something has actually gone wrong so there's no link state change
interrupt forthcoming regardless of how long you wait.
You bring up a good point. There is another place where we are noisier
with respect to the link being down, so we'll do the same here. I'll =
include
this in v5 along with an updated commit message as requested.