From: Matthew R. Ochs <hidden> Date: 2015-10-21 20:10:32
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 (rebased to Dan Carpenter's 9/22 patch) and is
intended for 4.4. The entire set is bisectable. Please reference the
changelog below for details on what has been altered from previous
versions of this patch set.
v6 Changes:
- Added patch to avoid corrupting the port selection mask
- Added patch to properly initialize the TMF spin lock
- Added patch to remove possibility of skipping context cleanup
- No change to patches present in v5
v5 Changes:
- Incorporate comments from Daniel Axtens
- Incorporate comments from Andrew Donnellan
- Added additional clarifications to several commit messages
- Specified some return codes as failures in "Fix function prolog..."
- Made port online failure noisier in "Remove dual port online..."
- Added patch to properly cleanup when encountering an unsupported AFU
- Added patch to escalate a link reset on login timeout
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 (5):
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
cxlflash: Fix to escalate to LINK_RESET on login timeout
Matthew R. Ochs (32):
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
cxlflash: Fix to avoid leaving dangling interrupt resources
cxlflash: Fix to avoid corrupting port selection mask
cxlflash: Fix to avoid lock instrumentation rejection
cxlflash: Fix to avoid bypassing context cleanup
MAINTAINERS | 9 +
drivers/scsi/cxlflash/common.h | 30 +-
drivers/scsi/cxlflash/lunmgt.c | 45 +-
drivers/scsi/cxlflash/main.c | 1550 ++++++++++++++++++++-----------------
drivers/scsi/cxlflash/main.h | 1 +
drivers/scsi/cxlflash/sislite.h | 8 +-
drivers/scsi/cxlflash/superpipe.c | 209 +++--
drivers/scsi/cxlflash/superpipe.h | 14 +-
drivers/scsi/cxlflash/vlun.c | 68 +-
9 files changed, 1075 insertions(+), 859 deletions(-)
--
2.1.0
From: Matthew R. Ochs <hidden> Date: 2015-10-21 20:12:15
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>
Reviewed-by: Tomas Henzl <redacted>
---
drivers/scsi/cxlflash/lunmgt.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
From: Matthew R. Ochs <hidden> Date: 2015-10-21 20:12:24
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>
Reviewed-by: Tomas Henzl <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-10-21 20:12:32
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>
Reviewed-by: Tomas Henzl <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-10-21 20:12:43
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>
Reviewed-by: Tomas Henzl <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-10-21 20:12:53
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>
Reviewed-by: Tomas Henzl <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-10-21 20:12:58
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>
Reviewed-by: Daniel Axtens <redacted>
Reviewed-by: Tomas Henzl <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-10-21 20:13:09
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>
Reviewed-by: Daniel Axtens <redacted>
Reviewed-by: Tomas Henzl <redacted>
---
drivers/scsi/cxlflash/superpipe.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
From: Matthew R. Ochs <hidden> Date: 2015-10-21 20:13:16
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>
Reviewed-by: Brian King <redacted>
Reviewed-by: Daniel Axtens <redacted>
Reviewed-by: Tomas Henzl <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-10-21 20:13:27
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>
Reviewed-by: Daniel Axtens <redacted>
Reviewed-by: Tomas Henzl <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-10-21 20:13:35
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>
Reviewed-by: Tomas Henzl <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-10-21 20:14:14
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-10-21 20:14:36
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. Lastly, one spelling
correction was made: 'entra' to 'extra'.
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>
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-10-21 20:14:44
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-10-21 20:14:53
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-10-21 20:15:02
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-10-21 20:15:11
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-10-21 20:15:18
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.
With this change, the card will be able 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.
Note that despite its void-like behavior, the function was left with a
return code for right now in case its behavior needs to be altered again
in the near future based on testing.
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
Reviewed-by: Brian King <redacted>
Reviewed-by: Daniel Axtens <redacted>
---
drivers/scsi/cxlflash/main.c | 27 ++++++++++-----------------
1 file changed, 10 insertions(+), 17 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_err("%s: wait on port %d to go online timed out\n",+__func__,port);}-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-10-21 20:15:24
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>
Reviewed-by: Daniel Axtens <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-10-21 20:15:31
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-10-21 20:15:40
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-10-21 20:15:50
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-10-21 20:16:00
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-10-21 20:16:03
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>
---
drivers/scsi/cxlflash/main.c | 70 ++++++++++++++++----------------------------
1 file changed, 26 insertions(+), 44 deletions(-)
From: Matthew R. Ochs <hidden> Date: 2015-10-21 20:16:12
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>
---
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-10-21 20:16:28
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>
---
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-10-21 20:16:29
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 will wait 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 potentially last forever (deadlock) if the
scsi_execute() that performs the read capacity experiences a
timeout and calls into the reset callback. When that occurs,
the reset callback sees that the device is already being reset
and waits for the reset to complete. This leaves two threads
waiting on the other.
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>
Reviewed-by: Daniel Axtens <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-10-21 20:16:38
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>
Reviewed-by: Daniel Axtens <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-10-21 20:16:46
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-10-21 20:16:52
From: Manoj Kumar <redacted>
The operator used to double the master context response 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>
---
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-10-21 20:17:00
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: Brian King <redacted>
Reviewed-by: Andrew Donnellan <redacted>
Reviewed-by: Daniel Axtens <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-10-21 20:17:07
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>
---
drivers/scsi/cxlflash/main.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
From: Matthew R. Ochs <hidden> Date: 2015-10-21 20:17:15
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>
Reviewed-by: Brian King <redacted>
Reviewed-by: Daniel Axtens <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: Matthew R. Ochs <hidden> Date: 2015-10-21 20:17:22
When running with an unsupported AFU, the cxlflash driver fails
the probe. When the driver is removed, the following Oops is
encountered on a show_interrupts() thread:
Call Trace:
[c000001fba5a7a10] [0000000000000003] 0x3 (unreliable)
[c000001fba5a7a60] [c00000000053dcf4] vsnprintf+0x204/0x4c0
[c000001fba5a7ae0] [c00000000030045c] seq_vprintf+0x5c/0xd0
[c000001fba5a7b20] [c00000000030051c] seq_printf+0x4c/0x60
[c000001fba5a7b50] [c00000000013e140] show_interrupts+0x370/0x4f0
[c000001fba5a7c10] [c0000000002ff898] seq_read+0xe8/0x530
[c000001fba5a7ca0] [c00000000035d5c0] proc_reg_read+0xb0/0x110
[c000001fba5a7cf0] [c0000000002ca74c] __vfs_read+0x6c/0x180
[c000001fba5a7d90] [c0000000002cb464] vfs_read+0xa4/0x1c0
[c000001fba5a7de0] [c0000000002cc51c] SyS_read+0x6c/0x110
[c000001fba5a7e30] [c000000000009204] system_call+0x38/0xb4
The Oops is due to not cleaning up correctly on the unsupported
AFU error path, leaving various allocated and registered resources.
In this case, interrupts are in a semi-allocated/registered state,
which the show_interrupts() thread attempts to use.
To fix, the cleanup logic in init_afu() is consolidated to error
gates at the bottom of the function and the appropriate goto is
added to each error path. As a mini side fix while refactoring
in this routine, the else statement following the AFU version
evaluation is eliminated as it is not needed.
Signed-off-by: Matthew R. Ochs <redacted>
Acked-by: Manoj Kumar <redacted>
Reviewed-by: Andrew Donnellan <redacted>
---
drivers/scsi/cxlflash/main.c | 28 ++++++++++++++++------------
1 file changed, 16 insertions(+), 12 deletions(-)
@@ -1721,15 +1721,14 @@ static int init_afu(struct cxlflash_cfg *cfg)if(rc){dev_err(dev,"%s: call to init_mc failed, rc=%d!\n",__func__,rc);-gotoerr1;+gotoout;}/* Map the entire MMIO space of the AFU */afu->afu_map=cxl_psa_map(cfg->mcctx);if(!afu->afu_map){-rc=-ENOMEM;-term_mc(cfg,UNDO_START);dev_err(dev,"%s: call to cxl_psa_map failed!\n",__func__);+rc=-ENOMEM;gotoerr1;}
@@ -1743,19 +1742,17 @@ static int init_afu(struct cxlflash_cfg *cfg)"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);+gotoerr2;+}++pr_debug("%s: afu version %s, interface version 0x%llX\n",__func__,+afu->version,afu->interface_version);rc=start_afu(cfg);if(rc){dev_err(dev,"%s: call to start_afu failed, rc=%d!\n",__func__,rc);-term_mc(cfg,UNDO_START);-cxl_psa_unmap((void__iomem*)afu->afu_map);-afu->afu_map=NULL;-gotoerr1;+gotoerr2;}afu_err_intr_init(cfg->afu);
@@ -1763,9 +1760,16 @@ static int init_afu(struct cxlflash_cfg *cfg)/* Restore the LUN mappings */cxlflash_restore_luntable(cfg);-err1:+out:pr_debug("%s: returning rc=%d\n",__func__,rc);returnrc;++err2:+cxl_psa_unmap((void__iomem*)afu->afu_map);+afu->afu_map=NULL;+err1:+term_mc(cfg,UNDO_START);+gotoout;}/**
From: Matthew R. Ochs <hidden> Date: 2015-10-21 20:17:31
From: Manoj Kumar <redacted>
A 'login timed out' asynchronous error interrupt is generated if no
response is seen to a FLOGI within 2 seconds. If the time out error
is not escalated to a LINK_RESET the port will not be available for
use. This fix provides the required escalation.
Signed-off-by: Manoj N. Kumar <redacted>
Acked-by: Matthew R. Ochs <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-10-21 20:17:45
The port selection mask of a LUN can be corrupted when the manage LUN
ioctl (DK_CXLFLASH_MANAGE_LUN) is issued more than once for any device.
This mask indicates to the AFU which port[s] can be used for a data
transfer to/from a particular LUN. The mask is critical to ensuring the
correct behavior when using the virtual LUN function of this adapter.
When the mask is configured for both ports, an I/O may be sent to either
port as the AFU assumes that each port has access to the same physical
device (specified by LUN ID in the port LUN table).
In a situation where the mask becomes incorrectly configured to reflect
access to both ports when in fact there is only access through a single
port, an I/O can be targeted to the wrong physical device. This can lead
to data corruption among other ill effects (e.g. security leaks).
The cause for this corruption is the assumption that the ioctl will only
be called a second time for a LUN when it is being configured for access
via a second port. A boolean 'newly_created' variable is used to
differentiate between a LUN that was created (and subsequently configured
for single port access) and one that is destined for access across both
ports. While initially set to 'true', this sticky boolean is toggled to
the 'false' state during a lookup on any next ioctl performed on a device
with a matching WWN/WWID. The code fails to realize that the match could
in fact be the same device calling in again. From here, an assumption is
made that any LUN with 'newly_created' set to 'false' is configured for
access over both ports and the port selection mask is set to reflect this.
Any future attempts to use this LUN for hosting a virtual LUN will result
in the port LUN table being incorrectly programmed.
As a remedy, the 'newly_created' concept was removed entirely and replaced
with code that always constructs the port selection mask based upon the
SCSI channel of the LUN being accessed. The bits remain sticky, therefore
allowing for a device to be accessed over both ports when that is in fact
the correct physical configuration.
Also included in this commit are a few minor related changes to enhance
the fix and provide better debug information for port selection mask and
port LUN table bugs in the future. These include renaming refresh_local()
to lookup_local(), tracing the WWN/WWID as a big-endian entity, and
tracing the port selection mask, SCSI channel, and LUN ID each time the
port LUN table is programmed.
Signed-off-by: Matthew R. Ochs <redacted>
---
drivers/scsi/cxlflash/lunmgt.c | 36 ++++++++++++++++++------------------
drivers/scsi/cxlflash/superpipe.h | 1 -
2 files changed, 18 insertions(+), 19 deletions(-)
@@ -63,7 +63,6 @@ struct llun_info {u32lun_index;/* Index in the LUN table */u32host_no;/* host_no from Scsi_host */u32port_sel;/* What port to use for this LUN */-boolnewly_created;/* Whether the LUN was just discovered */boolin_table;/* Whether a LUN table entry was created */u8wwid[16];/* Keep a duplicate copy here? */
From: Matthew R. Ochs <hidden> Date: 2015-10-21 20:17:47
When running with lock instrumentation (e.g. lockdep), some of the
instrumentation can become disabled at probe time for a cxlflash
adapter. This is due to a missing lock registration for the tmf_slock.
The fix is to call spin_lock_init() for the tmf_slock during probe.
Signed-off-by: Matthew R. Ochs <redacted>
---
drivers/scsi/cxlflash/main.c | 1 +
1 file changed, 1 insertion(+)
From: Matthew R. Ochs <hidden> Date: 2015-10-21 20:17:57
Contexts may be skipped over for cleanup in situations where contention
for the adapter's table-list mutex is experienced in the presence of a
signal during the execution of the release handler.
This can lead to two known issues:
- A hang condition on remove as that path tries to wait for users to
cleanup - something that will never complete should this scenario play
out as the user has already cleaned up from their perspective.
- An Oops in the unmap_mapping_range() call that is made as part of
the user waiting mechanism that is invoked on remove when contexts
are found to still exist.
The root cause of this issue can be found in get_context() and how the
table-list mutex is acquired. As this code path is shared by several
different access points within the driver, a decision was made during
the development cycle to acquire this mutex in this location using the
interruptible version of the mutex locking service. In almost all of
the use-cases and environmental scenarios this holds up, even when the
mutex is contended. However, for critical system threads (such as the
release handler), failing to acquire the mutex and bailing with the
intention of the user being able to try again later is unacceptable.
In such a scenario, the context _must_ be derived as it is on an
irreversible path to being freed. Without being able to derive the
context, the code mistakenly assumes that it has already been freed
and proceeds to free up the underlying CXL context resources. From
this point on, any usage of [the now stale] CXL context resources
will result in undefined behavior. This is root cause of the Oops
mentioned as the second known issue as the mapping passed to the
unmap_mapping_range() service is owned by the CXL context.
To fix this problem, acquisition of the table-list mutex within
get_context() is simply changed to use the uninterruptible version
of the mutex locking service. This is safe as the timing windows for
holding this mutex are short and also protected against blocking.
Signed-off-by: Matthew R. Ochs <redacted>
---
drivers/scsi/cxlflash/superpipe.c | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
From: Andrew Donnellan <hidden> Date: 2015-10-22 02:02:33
On 22/10/15 07:16, Matthew R. Ochs wrote:
Contexts may be skipped over for cleanup in situations where contention
for the adapter's table-list mutex is experienced in the presence of a
signal during the execution of the release handler.
This can lead to two known issues:
- A hang condition on remove as that path tries to wait for users to
cleanup - something that will never complete should this scenario play
out as the user has already cleaned up from their perspective.
- An Oops in the unmap_mapping_range() call that is made as part of
the user waiting mechanism that is invoked on remove when contexts
are found to still exist.
The root cause of this issue can be found in get_context() and how the
table-list mutex is acquired. As this code path is shared by several
different access points within the driver, a decision was made during
the development cycle to acquire this mutex in this location using the
interruptible version of the mutex locking service. In almost all of
the use-cases and environmental scenarios this holds up, even when the
mutex is contended. However, for critical system threads (such as the
release handler), failing to acquire the mutex and bailing with the
intention of the user being able to try again later is unacceptable.
In such a scenario, the context _must_ be derived as it is on an
irreversible path to being freed. Without being able to derive the
context, the code mistakenly assumes that it has already been freed
and proceeds to free up the underlying CXL context resources. From
this point on, any usage of [the now stale] CXL context resources
will result in undefined behavior. This is root cause of the Oops
mentioned as the second known issue as the mapping passed to the
unmap_mapping_range() service is owned by the CXL context.
To fix this problem, acquisition of the table-list mutex within
get_context() is simply changed to use the uninterruptible version
of the mutex locking service. This is safe as the timing windows for
holding this mutex are short and also protected against blocking.
Signed-off-by: Matthew R. Ochs <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
Acked-by: Manoj Kumar <redacted>
On 10/21/2015 3:16 PM, Matthew R. Ochs wrote:
When running with lock instrumentation (e.g. lockdep), some of the
instrumentation can become disabled at probe time for a cxlflash
adapter. This is due to a missing lock registration for the tmf_slock.
The fix is to call spin_lock_init() for the tmf_slock during probe.
Acked-by: Manoj Kumar <redacted>
On 10/21/2015 3:16 PM, Matthew R. Ochs wrote:
Contexts may be skipped over for cleanup in situations where contention
for the adapter's table-list mutex is experienced in the presence of a
signal during the execution of the release handler.
From: Andrew Donnellan <hidden> Date: 2015-10-23 03:22:52
On 22/10/15 07:16, Matthew R. Ochs wrote:
When running with lock instrumentation (e.g. lockdep), some of the
instrumentation can become disabled at probe time for a cxlflash
adapter. This is due to a missing lock registration for the tmf_slock.
The fix is to call spin_lock_init() for the tmf_slock during probe.
Signed-off-by: Matthew R. Ochs <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-10-23 03:41:27
On 22/10/15 07:13, Matthew R. Ochs wrote:
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>
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-10-23 03:52:33
On 22/10/15 07:16, Matthew R. Ochs wrote:
The port selection mask of a LUN can be corrupted when the manage LUN
ioctl (DK_CXLFLASH_MANAGE_LUN) is issued more than once for any device.
> ...
Signed-off-by: Matthew R. Ochs <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: Tomas Henzl <hidden> Date: 2015-10-23 13:33:20
On 21.10.2015 22:12, 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>
From: Tomas Henzl <hidden> Date: 2015-10-23 13:33:51
On 21.10.2015 22:13, 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. Lastly, one spelling
correction was made: 'entra' to 'extra'.
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>
From: Tomas Henzl <hidden> Date: 2015-10-23 13:36:51
On 21.10.2015 22:13, Matthew R. Ochs wrote:
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>
From: Tomas Henzl <hidden> Date: 2015-10-23 13:37:36
On 21.10.2015 22:13, Matthew R. Ochs wrote:
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>
From: Tomas Henzl <hidden> Date: 2015-10-23 13:38:28
On 21.10.2015 22:13, Matthew R. Ochs wrote:
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>
From: Tomas Henzl <hidden> Date: 2015-10-23 13:39:09
On 21.10.2015 22:13, Matthew R. Ochs wrote:
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>
From: Tomas Henzl <hidden> Date: 2015-10-23 13:39:40
On 21.10.2015 22:13, Matthew R. Ochs wrote:
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.
With this change, the card will be able 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.
Note that despite its void-like behavior, the function was left with a
return code for right now in case its behavior needs to be altered again
in the near future based on testing.
Signed-off-by: Matthew R. Ochs <redacted>
Signed-off-by: Manoj N. Kumar <redacted>
Reviewed-by: Brian King <redacted>
Reviewed-by: Daniel Axtens <redacted>
From: Tomas Henzl <hidden> Date: 2015-10-23 13:40:12
On 21.10.2015 22:14, Matthew R. Ochs wrote:
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>
Reviewed-by: Daniel Axtens <redacted>
From: Tomas Henzl <hidden> Date: 2015-10-23 13:41:07
On 21.10.2015 22:14, Matthew R. Ochs wrote:
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>
From: Tomas Henzl <hidden> Date: 2015-10-23 13:41:39
On 21.10.2015 22:14, Matthew R. Ochs wrote:
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>
From: Tomas Henzl <hidden> Date: 2015-10-23 13:42:05
On 21.10.2015 22:14, Matthew R. Ochs wrote:
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>
From: Tomas Henzl <hidden> Date: 2015-10-23 13:42:25
On 21.10.2015 22:14, Matthew R. Ochs wrote:
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>
From: Tomas Henzl <hidden> Date: 2015-10-23 13:45:08
On 21.10.2015 22:14, 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>
From: Tomas Henzl <hidden> Date: 2015-10-23 13:53:24
On 21.10.2015 22:14, 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>
From: Tomas Henzl <hidden> Date: 2015-10-23 13:54:14
On 21.10.2015 22:14, Matthew R. Ochs wrote:
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 will wait 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 potentially last forever (deadlock) if the
scsi_execute() that performs the read capacity experiences a
timeout and calls into the reset callback. When that occurs,
the reset callback sees that the device is already being reset
and waits for the reset to complete. This leaves two threads
waiting on the other.
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>
Reviewed-by: Daniel Axtens <redacted>
From: Tomas Henzl <hidden> Date: 2015-10-23 13:55:02
On 21.10.2015 22:15, 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>
From: Tomas Henzl <hidden> Date: 2015-10-23 13:55:29
On 21.10.2015 22:15, Matthew R. Ochs wrote:
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>
Reviewed-by: Daniel Axtens <redacted>
From: Tomas Henzl <hidden> Date: 2015-10-23 13:57:43
On 21.10.2015 22:15, Matthew R. Ochs wrote:
From: Manoj Kumar <redacted>
The operator used to double the master context response 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>
From: Tomas Henzl <hidden> Date: 2015-10-23 14:00:07
On 21.10.2015 22:15, 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: Brian King <redacted>
Reviewed-by: Andrew Donnellan <redacted>
Reviewed-by: Daniel Axtens <redacted>
From: Tomas Henzl <hidden> Date: 2015-10-23 14:00:23
On 21.10.2015 22:15, 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>
From: Tomas Henzl <hidden> Date: 2015-10-23 14:01:17
On 21.10.2015 22:15, Matthew R. Ochs wrote:
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>
Reviewed-by: Brian King <redacted>
Reviewed-by: Daniel Axtens <redacted>
From: Tomas Henzl <hidden> Date: 2015-10-23 14:01:41
On 21.10.2015 22:16, Matthew R. Ochs wrote:
When running with an unsupported AFU, the cxlflash driver fails
the probe. When the driver is removed, the following Oops is
encountered on a show_interrupts() thread:
Call Trace:
[c000001fba5a7a10] [0000000000000003] 0x3 (unreliable)
[c000001fba5a7a60] [c00000000053dcf4] vsnprintf+0x204/0x4c0
[c000001fba5a7ae0] [c00000000030045c] seq_vprintf+0x5c/0xd0
[c000001fba5a7b20] [c00000000030051c] seq_printf+0x4c/0x60
[c000001fba5a7b50] [c00000000013e140] show_interrupts+0x370/0x4f0
[c000001fba5a7c10] [c0000000002ff898] seq_read+0xe8/0x530
[c000001fba5a7ca0] [c00000000035d5c0] proc_reg_read+0xb0/0x110
[c000001fba5a7cf0] [c0000000002ca74c] __vfs_read+0x6c/0x180
[c000001fba5a7d90] [c0000000002cb464] vfs_read+0xa4/0x1c0
[c000001fba5a7de0] [c0000000002cc51c] SyS_read+0x6c/0x110
[c000001fba5a7e30] [c000000000009204] system_call+0x38/0xb4
The Oops is due to not cleaning up correctly on the unsupported
AFU error path, leaving various allocated and registered resources.
In this case, interrupts are in a semi-allocated/registered state,
which the show_interrupts() thread attempts to use.
To fix, the cleanup logic in init_afu() is consolidated to error
gates at the bottom of the function and the appropriate goto is
added to each error path. As a mini side fix while refactoring
in this routine, the else statement following the AFU version
evaluation is eliminated as it is not needed.
Signed-off-by: Matthew R. Ochs <redacted>
Acked-by: Manoj Kumar <redacted>
Reviewed-by: Andrew Donnellan <redacted>
From: Tomas Henzl <hidden> Date: 2015-10-23 14:01:57
On 21.10.2015 22:16, Matthew R. Ochs wrote:
From: Manoj Kumar <redacted>
A 'login timed out' asynchronous error interrupt is generated if no
response is seen to a FLOGI within 2 seconds. If the time out error
is not escalated to a LINK_RESET the port will not be available for
use. This fix provides the required escalation.
Signed-off-by: Manoj N. Kumar <redacted>
Acked-by: Matthew R. Ochs <redacted>
Reviewed-by: Brian King <redacted>
From: Matthew R. Ochs <hidden> Date: 2015-10-27 23:31:01
Hi James,
This series has been reviewed/acked. Is there anything else you're =
looking
for before this can make it into -next?
-matt
On Oct 21, 2015, at 3:08 PM, Matthew R. Ochs =
[off-list ref] wrote:
=20
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 (rebased to Dan Carpenter's 9/22 patch) and is
intended for 4.4. The entire set is bisectable. Please reference the
changelog below for details on what has been altered from previous
versions of this patch set.
=20
v6 Changes:
- Added patch to avoid corrupting the port selection mask
- Added patch to properly initialize the TMF spin lock
- Added patch to remove possibility of skipping context cleanup
- No change to patches present in v5
=20
v5 Changes:
- Incorporate comments from Daniel Axtens
- Incorporate comments from Andrew Donnellan
- Added additional clarifications to several commit messages
- Specified some return codes as failures in "Fix function prolog..."
- Made port online failure noisier in "Remove dual port online..."
- Added patch to properly cleanup when encountering an unsupported AFU
- Added patch to escalate a link reset on login timeout
=20
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..."
=20
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
=20
v2 Changes:
- Incorporate comments from Ian Munsie
- Rework commit messages to be more descriptive
- Add state change serialization patch
=20
Manoj Kumar (5):
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
cxlflash: Fix to escalate to LINK_RESET on login timeout
=20
Matthew R. Ochs (32):
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
cxlflash: Fix to avoid leaving dangling interrupt resources
cxlflash: Fix to avoid corrupting port selection mask
cxlflash: Fix to avoid lock instrumentation rejection
cxlflash: Fix to avoid bypassing context cleanup
=20
MAINTAINERS | 9 +
drivers/scsi/cxlflash/common.h | 30 +-
drivers/scsi/cxlflash/lunmgt.c | 45 +-
drivers/scsi/cxlflash/main.c | 1550 =
++++++++++++++++++++-----------------
drivers/scsi/cxlflash/main.h | 1 +
drivers/scsi/cxlflash/sislite.h | 8 +-
drivers/scsi/cxlflash/superpipe.c | 209 +++--
drivers/scsi/cxlflash/superpipe.h | 14 +-
drivers/scsi/cxlflash/vlun.c | 68 +-
9 files changed, 1075 insertions(+), 859 deletions(-)
=20
--=20
2.1.0
=20
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" =