Re: [PATCH 09/11] target_core_alua: Use workqueue for ALUA transitioning
On 10/17/2013 12:06 AM, Nicholas A. Bellinger wrote: > On Wed, 2013-10-16 at 09:20 +0200, Hannes Reinecke wrote: >> Use a workqueue for processing ALUA state transitions; this allows >> us to process implicit delay properly. >> >> Signed-off-by: Hannes Reinecke >> --- >> drivers/target/target_core_alua.c | 174 >> +++--- >> include/target/target_core_base.h | 4 + >> 2 files changed, 128 insertions(+), 50 deletions(-) >> > > > >> +static int core_alua_do_transition_tg_pt( >> +struct t10_alua_tg_pt_gp *tg_pt_gp, >> +int new_state, >> +int explicit) >> +{ >> +struct se_device *dev = tg_pt_gp->tg_pt_gp_dev; >> +DECLARE_COMPLETION_ONSTACK(wait); >> + >> +/* Nothing to be done here */ >> +if (atomic_read(&tg_pt_gp->tg_pt_gp_alua_access_state) == new_state) >> +return 0; >> + >> +if (new_state == ALUA_ACCESS_STATE_TRANSITION) >> +return -EAGAIN; >> + >> +/* >> + * Flush any pending transitions >> + */ >> +if (!explicit && tg_pt_gp->tg_pt_gp_implicit_trans_secs && >> +atomic_read(&tg_pt_gp->tg_pt_gp_alua_access_state) == >> +ALUA_ACCESS_STATE_TRANSITION) { >> +/* Just in case */ >> +tg_pt_gp->tg_pt_gp_alua_pending_state = new_state; >> +tg_pt_gp->tg_pt_gp_transition_complete = &wait; >> +flush_delayed_work(&tg_pt_gp->tg_pt_gp_transition_work); >> +wait_for_completion(&wait); >> +tg_pt_gp->tg_pt_gp_transition_complete = NULL; >> +return 0; >> +} >> + >> +/* >> + * Save the old primary ALUA access state, and set the current state >> + * to ALUA_ACCESS_STATE_TRANSITION. >> + */ >> +tg_pt_gp->tg_pt_gp_alua_previous_state = >> +atomic_read(&tg_pt_gp->tg_pt_gp_alua_access_state); >> +tg_pt_gp->tg_pt_gp_alua_pending_state = new_state; >> + >> +atomic_set(&tg_pt_gp->tg_pt_gp_alua_access_state, >> +ALUA_ACCESS_STATE_TRANSITION); >> +tg_pt_gp->tg_pt_gp_alua_access_status = (explicit) ? >> +ALUA_STATUS_ALTERED_BY_EXPLICIT_STPG : >> +ALUA_STATUS_ALTERED_BY_IMPLICIT_ALUA; >> + >> +/* >> + * Check for the optional ALUA primary state transition delay >> + */ >> +if (tg_pt_gp->tg_pt_gp_trans_delay_msecs != 0) >> +msleep_interruptible(tg_pt_gp->tg_pt_gp_trans_delay_msecs); >> + >> +/* >> + * Take a reference for workqueue item >> + */ >> +spin_lock(&dev->t10_alua.tg_pt_gps_lock); >> +atomic_inc(&tg_pt_gp->tg_pt_gp_ref_cnt); >> +smp_mb__after_atomic_inc(); >> +spin_unlock(&dev->t10_alua.tg_pt_gps_lock); >> + >> +if (!explicit && tg_pt_gp->tg_pt_gp_implicit_trans_secs) { >> +unsigned long transition_tmo; >> + >> +transition_tmo = tg_pt_gp->tg_pt_gp_implicit_trans_secs * HZ; >> +queue_delayed_work(tg_pt_gp->tg_pt_gp_dev->tmr_wq, >> + &tg_pt_gp->tg_pt_gp_transition_work, >> + transition_tmo); >> +} else { >> +tg_pt_gp->tg_pt_gp_transition_complete = &wait; >> +queue_delayed_work(tg_pt_gp->tg_pt_gp_dev->tmr_wq, >> + &tg_pt_gp->tg_pt_gp_transition_work, 0); >> +wait_for_completion(&wait); >> +tg_pt_gp->tg_pt_gp_transition_complete = NULL; >> +} > > Mmm, the trans_delay_msecs delay seems a bit out of place now.. > > How about dropping it's usage with msleep_interruptible() above, and > instead combining it with the delay passed into queue_delayed_work()..? > Yeah, we could. Actually I was thinking of opening up the implicit transition time to be a general transitioning time, to be used for both implicit and explicit. Reasoning here is that one could kick off a userland tool once 'transitioning' mode has been requested. That tool would then go ahead and do whatever is required to switch paths around etc, and could write the final ALUA state into configfs. That would then terminate the workqueue and the system would continue with the new state. If the userland tool fails to execute in time the system would revert to the requested state as it does now. The only problem with that approach is that it's currently impossible to have an atomic implicit transition for several tpgs. You can to an atomic _explicit_ transition, as SET TARGET PORT GROUPS _can_ carry information about all target port groups. (Mind you, scsi_dh_alua doesn't use it that way, it only sends information for the active/optimized target port group). But you cannot achieve a similar operation via configfs; there you can only set one tpg at a time, and each of this will potentially trigger a move to transitioning. While this is not a violation of the spec, it is certainly confusing. I'd rather have a way to set the new state for _all_ tpgs at once and only then kick off the transitioning mechanism. Any
Re: [PATCH 02/11] target_core_alua: Store supported ALUA states
On 10/16/2013 11:19 PM, Nicholas A. Bellinger wrote: > On Wed, 2013-10-16 at 09:20 +0200, Hannes Reinecke wrote: >> The supported ALUA states might be different for individual >> devices, so store it in a separate field. >> >> Signed-off-by: Hannes Reinecke >> --- >> drivers/target/target_core_alua.c | 14 -- >> drivers/target/target_core_alua.h | 11 +++ >> include/target/target_core_base.h | 1 + >> 3 files changed, 20 insertions(+), 6 deletions(-) >> >> diff --git a/drivers/target/target_core_alua.c >> b/drivers/target/target_core_alua.c >> index 8297d37..255e83c 100644 >> --- a/drivers/target/target_core_alua.c >> +++ b/drivers/target/target_core_alua.c >> @@ -117,12 +117,7 @@ target_emulate_report_target_port_groups(struct se_cmd >> *cmd) >> /* >> * Set supported ASYMMETRIC ACCESS State bits >> */ >> -buf[off] = 0x80; /* T_SUP */ >> -buf[off] |= 0x40; /* O_SUP */ >> -buf[off] |= 0x8; /* U_SUP */ >> -buf[off] |= 0x4; /* S_SUP */ >> -buf[off] |= 0x2; /* AN_SUP */ >> -buf[off++] |= 0x1; /* AO_SUP */ >> +buf[off++] |= tg_pt_gp->tg_pt_gp_alua_supported_states; >> /* >> * TARGET PORT GROUP >> */ >> @@ -1367,6 +1362,13 @@ struct t10_alua_tg_pt_gp >> *core_alua_allocate_tg_pt_gp(struct se_device *dev, >> tg_pt_gp->tg_pt_gp_trans_delay_msecs = ALUA_DEFAULT_TRANS_DELAY_MSECS; >> tg_pt_gp->tg_pt_gp_implicit_trans_secs = >> ALUA_DEFAULT_IMPLICIT_TRANS_SECS; >> >> +/* >> + * Enable all supported states >> + */ >> +tg_pt_gp->tg_pt_gp_alua_supported_states = >> +ALUA_T_SUP | ALUA_O_SUP | \ >> +ALUA_U_SUP | ALUA_S_SUP | ALUA_AN_SUP | ALUA_AO_SUP; >> + >> if (def_group) { >> spin_lock(&dev->t10_alua.tg_pt_gps_lock); >> tg_pt_gp->tg_pt_gp_id = >> diff --git a/drivers/target/target_core_alua.h >> b/drivers/target/target_core_alua.h >> index 74cf0c0..e826a65 100644 >> --- a/drivers/target/target_core_alua.h >> +++ b/drivers/target/target_core_alua.h >> @@ -23,6 +23,17 @@ >> #define ALUA_ACCESS_STATE_TRANSITION0xf >> >> /* >> + * from spc4r36j section 6.37 Table 306 >> + */ >> +#define ALUA_T_SUP 0x80 >> +#define ALUA_O_SUP 0x40 >> +#define ALUA_LBD_SUP0x10 >> +#define ALUA_U_SUP 0x08 >> +#define ALUA_S_SUP 0x04 >> +#define ALUA_AN_SUP 0x02 >> +#define ALUA_AO_SUP 0x01 >> + >> +/* > > How about making these the supported bits, TPGS mode, and ALUA access > state definitions common between target_core_alua.c and > scsi_dh_alua.c..? > Sure. Good idea. Cheers, Hannes -- Dr. Hannes Reinecke zSeries & Storage h...@suse.de +49 911 74053 688 SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg) -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
RE: [PATCH][SCSI] megaraid_sas: Fix synchronization problem between sysPD IO path and AEN path
>-Original Message- >From: James Bottomley [mailto:jbottom...@parallels.com] >Sent: Thursday, October 17, 2013 3:15 AM >To: Saxena, Sumit >Cc: linux-scsi@vger.kernel.org; Desai, Kashyap; aradf...@gmail.com >Subject: Re: [PATCH][SCSI] megaraid_sas: Fix synchronization problem >between sysPD IO path and AEN path > >On Wed, 2013-10-16 at 17:04 +0530, sumit.sax...@lsi.com wrote: >> There is syncronization problem between sysPD IO path and AEN path. >> Driver maintains instance->pd_list[] array, which will get updated(by >> calling function megasas_get_pd_list[]), whenever any of below events >> occurs- >> >> MR_EVT_PD_INSERTED >> MR_EVT_PD_REMOVED >> MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED >> MR_EVT_FOREIGN_CFG_IMPORTED >> >> At same time running sysPD IO will be accessing the same array >> instance->pd_list[], which is getting updated in AEN path, because of >this IO may not get correct PD info from instance->pd_list[] array. >> >> Signed-off-by: Adam Radford >> Signed-off-by: Sumit Saxena > >Explain the signoff chain: is this a joinly authored patch? Yes, it's jointly authored patch. Originally, this patch is authored by Adam Radford, and then modified by me(Sumit Saxena). > >James > -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
RE: [PATCH Resend] [scsi] pm8001 : fix panic when cat /sys/class/sas_phy/phy-8:0/running_disparity_error_count
> diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_h > wi.c index 9f91030..c0ea473 100644 > --- a/drivers/scsi/pm8001/pm80xx_hwi.c > +++ b/drivers/scsi/pm8001/pm80xx_hwi.c > @@ -3076,8 +3076,43 @@ static int mpi_get_controller_config_resp(struct pm80 > 01_hba_info *pm8001_ha, > static int mpi_get_phy_profile_resp(struct pm8001_hba_info *pm8001_ha, > void *piomb) > { > - PM8001_MSG_DBG(pm8001_ha, > - pm8001_printk(" pm80xx_addition_functionality\n")); > + u8 page_code; > + struct get_phy_profile_resp *pPayload = (struct get_phy_profile_resp > + *)(piomb + 4); > + u32 ppc_phyid = le32_to_cpu(pPayload->ppc_phyid); > + u32 status = le32_to_cpu(pPayload->status); > + u8 phy_id = (u8)(ppc_phyid & 0x00FF); > + page_code = (u8)((ppc_phyid & 0xFF00) >> 8); struct asd_sas_phy > + *sas_phy = &(pm8001_ha->phy[phy_id].sas_phy); > + struct sas_phy *phy = sas_phy->phy; > + > + if (status) { > + /* status is FAILED */ > + PM8001_FAIL_DBG(pm8001_ha, > + pm8001_printk("PhyProfile command failed with status " > + "0x%08X \n", status)); > + return -1; > + } else { > + switch (page_code) { > + case SAS_PHY_ERROR_PAGE: > + phy->invalid_dword_count = > + le32_to_cpu(pPayload->ppc_specific_rsp[0]); > + phy->running_disparity_error_count = > + le32_to_cpu(pPayload->ppc_specific_rsp[1]); > + phy->loss_of_dword_sync_count = > + le32_to_cpu(pPayload->ppc_specific_rsp[3]); > + phy->phy_reset_problem_count = > + le32_to_cpu(pPayload->ppc_specific_rsp[4]); > + complete(pm8001_ha->phy[phy_id].enable_completion); > + break; > + default: > + PM8001_MSG_DBG(pm8001_ha, > + pm8001_printk("other page code 0x%X\n", page_code)); break; } } > > return 0; > } Any failure response also need to call complete() function. You can put the "complete()" at end before return. Thanks. Lindar -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 3/3] Fix device detection issues with mvsas driver
The only way to reproduce this is to keep hot plugging drives. To speed it up once in a while remove the drive before the detection completes. > On Oct 16, 2013, at 7:42 PM, "xiangliang yu" wrote: > > Hi, > > >Subject: Re: [PATCH 3/3] Fix device detection issues with mvsas driver > > >Hi Xiang, Can you please take a look at the attached patch and ack it? > > /* cleanup and prepare the allocated FIS index */ > > memset( SATA_RECEIVED_D2H_FIS(mvi_dev->taskfileset), 0, > > sizeof(struct dev_to_host_fis) ); > > According to spec, the FIS memory don't need to be cleared by software. > can you tell me how to reproduce the issue? thanks! > > -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [Bug] 12.864681 BUG: lock held when returning to user space!
On 10/17/2013 06:41 AM, Douglas Gilbert wrote: > That seems to be the case. Vaughan acknowledged the > problem and forwarded it to me 8 days ago. Yes, it > seems to be a "no-no" to hold a any kernel semaphore > when returning to the user space; in this case from > sg_open(). I was hoping a revised patch might > appear from Vaughan but to date that has not been > the case. So with only a few weeks to go before > lk 3.12 is released, reverting the whole 4 patches > in that series seems to be the safest course. > > Also without a new patch from Vaughan in the next few > weeks he may also miss the opportunity of getting > his improved O_EXCL logic into the lk 3.13 series. > > > Thinking about how to solve this problem: a field could > be added to 'struct sg_device' with one of three states: > no_opens, non_excl_opens and excl_open. It could be > manipulated by sg_open() and sg_release() like a > read-write semaphore. And the faulty 'struct > rw_semaphore o_sem' in sg_device could be replaced by a > normal semaphore to protect the manipulation of the new > three-state field. > And the new three-state field would replace (or expand) the 'char exclude' field in struct sg_device . > > Doug Gilbert Hi Doug, Thanks for providing advice on how to fix this. However, it seems be still awkward somehow. We have to 1. hold a lock (maybe sg_index_lock or a new one) 2. check a) the new three-state field; b) if sfp list is empty; c) sdp->detached field; if either condition fails, we may link the open process into o_excl_wait queue and need wakeup. if satisfied, we go on. 3. then we release at least sg_index_lock to malloc a new sfp and initialize. 4. try to acquire sg_index_lock again and add this sfp into sfd_siblings list if possible. <== We still have to check at least sdp->detached field 5. update three-state field to reflect the result of Step 4, and wake up processes waiting in o_excl_wait. This uncomfortable is introduced by releasing the sg_index_lock in the middle of check->malloc->add the new sfp struct. I wanna ask if it is possible to split the sg_add_sfp() into two functions, sg_init_sfp() and sg_add_sfp2(). We can do all initialize work in sg_init_sfp() without any lock and let sg_add_sfp2() only serve lock-check-add in one way. It seems more convenient for me to understand. But there is still some questions on this approach: 1. memory consume can be very large if lots of sg_init_sfp in the same time; 2. some field are initialized according to the fields of scsi device sdp points to, such as low_dma, sg_tablesize, max_sector, phys_segs. I know scsi_device_get() would keep the underlying scsi_device alive, however would these fields change in the gap of our initialize and add? The relationship of sg_device and scsi_device like above said confuse me somehow... Thanks, Vaughan -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/2] target_core_alua: Referrals configfs integration
On Wed, 2013-10-16 at 09:25 +0200, Hannes Reinecke wrote: > Referrals need an LBA map, which needs to be kept > consistent across all target port groups. So > instead of tying the map to the target port groups > I've implemented a single attribute containing the > entire map. > > Signed-off-by: Hannes Reinecke > --- > drivers/target/target_core_alua.c | 101 +++ > drivers/target/target_core_alua.h | 8 ++ > drivers/target/target_core_configfs.c | 171 > + > drivers/target/target_core_device.c| 1 + > drivers/target/target_core_transport.c | 28 +- > 5 files changed, 308 insertions(+), 1 deletion(-) > > diff --git a/drivers/target/target_core_alua.c > b/drivers/target/target_core_alua.c > index 8f66146..9dd01ff 100644 > --- a/drivers/target/target_core_alua.c > +++ b/drivers/target/target_core_alua.c > @@ -1340,6 +1340,107 @@ static int core_alua_set_tg_pt_secondary_state( > return 0; > } > > +struct t10_alua_lba_map * > +core_alua_allocate_lba_map(struct list_head *list, > +u64 first_lba, u64 last_lba) > +{ > + struct t10_alua_lba_map *lba_map; > + > + lba_map = kmem_cache_zalloc(t10_alua_lba_map_cache, GFP_KERNEL); > + if (!lba_map) { > + pr_err("Unable to allocate struct t10_alua_lba_map\n"); > + return ERR_PTR(-ENOMEM); > + } > + INIT_LIST_HEAD(&lba_map->lba_map_mem_list); > + lba_map->lba_map_first_lba = first_lba; > + lba_map->lba_map_last_lba = last_lba; > + > + list_add_tail(&lba_map->lba_map_list, list); > + return lba_map; > +} This list_add_tail needs to be protected, no..? > + > +int > +core_alua_allocate_lba_map_mem(struct t10_alua_lba_map *lba_map, > +int pg_id, int state) > +{ > + struct t10_alua_lba_map_member *lba_map_mem; > + > + list_for_each_entry(lba_map_mem, &lba_map->lba_map_mem_list, > + lba_map_mem_list) { > + if (lba_map_mem->lba_map_mem_alua_pg_id == pg_id) { > + pr_err("Duplicate pg_id %d in lba_map\n", pg_id); > + return -EINVAL; > + } > + } > + > + lba_map_mem = kmem_cache_zalloc(t10_alua_lba_map_mem_cache, GFP_KERNEL); > + if (!lba_map_mem) { > + pr_err("Unable to allocate struct t10_alua_lba_map_mem\n"); > + return -ENOMEM; > + } > + lba_map_mem->lba_map_mem_alua_state = state; > + lba_map_mem->lba_map_mem_alua_pg_id = pg_id; > + > + list_add_tail(&lba_map_mem->lba_map_mem_list, > + &lba_map->lba_map_mem_list); > + return 0; > +} Ditto here.. > + > +void > +core_alua_free_lba_map(struct list_head *lba_list) > +{ > + struct t10_alua_lba_map *lba_map, *lba_map_tmp; > + struct t10_alua_lba_map_member *lba_map_mem, *lba_map_mem_tmp; > + > + list_for_each_entry_safe(lba_map, lba_map_tmp, lba_list, > + lba_map_list) { > + list_for_each_entry_safe(lba_map_mem, lba_map_mem_tmp, > + &lba_map->lba_map_mem_list, > + lba_map_mem_list) { > + list_del(&lba_map_mem->lba_map_mem_list); > + kmem_cache_free(t10_alua_lba_map_mem_cache, > + lba_map_mem); > + } > + list_del(&lba_map->lba_map_list); > + kmem_cache_free(t10_alua_lba_map_cache, lba_map); > + } > +} And here.. > + > +void > +core_alua_set_lba_map(struct se_device *dev, struct list_head *lba_map_list, > + int segment_size, int segment_mult) > +{ > + struct list_head old_lba_map_list; > + struct t10_alua_tg_pt_gp *tg_pt_gp; > + int activate = 0, supported; > + > + INIT_LIST_HEAD(&old_lba_map_list); > + spin_lock(&dev->t10_alua.lba_map_lock); > + dev->t10_alua.lba_map_segment_size = segment_size; > + dev->t10_alua.lba_map_segment_multiplier = segment_mult; > + list_splice_init(&dev->t10_alua.lba_map_list, &old_lba_map_list); > + if (lba_map_list) { > + list_splice_init(lba_map_list, &dev->t10_alua.lba_map_list); > + activate = 1; > + } > + spin_unlock(&dev->t10_alua.lba_map_lock); > + spin_lock(&dev->t10_alua.tg_pt_gps_lock); > + list_for_each_entry(tg_pt_gp, &dev->t10_alua.tg_pt_gps_list, > + tg_pt_gp_list) { > + > + if (!tg_pt_gp->tg_pt_gp_valid_id) > + continue; > + supported = tg_pt_gp->tg_pt_gp_alua_supported_states; > + if (activate) > + supported |= ALUA_LBD_SUP; > + else > + supported &= ~ALUA_LBD_SUP; > + tg_pt_gp->tg_pt_gp_alua_supported_states = supported; > + } > + spin_unlock(&dev->t10_alua.tg_pt_gps_lock); > + core_alua_free_lba_map(&old_lba_map_list); > +} > + > struct
Re: [Bug] 12.864681 BUG: lock held when returning to user space!
On 13-10-16 09:24 AM, James Bottomley wrote: On Tue, 2013-10-08 at 09:45 -0400, Douglas Gilbert wrote: On 13-10-08 02:44 AM, vaughan wrote: Hi Madper, CC to Douglas to get comments. I use the rw_semaphore o_sem to protect excl open, introduced in commit 15b06f9a02406e5460001db6d5af5c738cd3d4e7 since v3.12-rc1. Is it forbidden to do like that in kernel?... It appears you can not (allow sg_open() to hold a semaphore then return to the user space). So you will need to do some rework on that patch or revert it. OK, there being no reply on this, I'll do the revert ... that's all four patches, correct? That seems to be the case. Vaughan acknowledged the problem and forwarded it to me 8 days ago. Yes, it seems to be a "no-no" to hold a any kernel semaphore when returning to the user space; in this case from sg_open(). I was hoping a revised patch might appear from Vaughan but to date that has not been the case. So with only a few weeks to go before lk 3.12 is released, reverting the whole 4 patches in that series seems to be the safest course. Also without a new patch from Vaughan in the next few weeks he may also miss the opportunity of getting his improved O_EXCL logic into the lk 3.13 series. Thinking about how to solve this problem: a field could be added to 'struct sg_device' with one of three states: no_opens, non_excl_opens and excl_open. It could be manipulated by sg_open() and sg_release() like a read-write semaphore. And the faulty 'struct rw_semaphore o_sem' in sg_device could be replaced by a normal semaphore to protect the manipulation of the new three-state field. Doug Gilbert -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] target: Pass through I/O topology for block backstores
On 10/12/2013 01:08 AM, Christoph Hellwig wrote: On Fri, Oct 11, 2013 at 11:52:53AM -0700, Andy Grover wrote: It seemed better to me to keep the munging from queue_limits values to what the target core needed in the block backstore code, and not use a block-specific structure in the backstore<->core interface. It looks like a few includes of blkdev.h slipped into target core, but these can be removed safely -- lio core doesn't depend on the block layer. We could define a new struct to get the 4 values at once, but it didn't seem worth it, esp. since two are only needed by emulate_readcapacity16, and the other two only by emulate_evpd_b0. I really don't like the influx of methods. But given thsat you have done the work I'd say merge your patch for now and then we can later see if we can come up with something more elegant. Nick, any cleaner ways to implement this come to mind? Happy to respin. If not, please apply. Regards -- Andy -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 1/2] target_core_alua: Referrals infrastructure
On Wed, 2013-10-16 at 09:25 +0200, Hannes Reinecke wrote: > Add infrastructure for referrals. > > Signed-off-by: Hannes Reinecke > --- > drivers/target/target_core_alua.c | 151 > ++ > drivers/target/target_core_alua.h | 4 +- > drivers/target/target_core_configfs.c | 12 ++- > drivers/target/target_core_device.c | 2 + > drivers/target/target_core_sbc.c | 5 +- > drivers/target/target_core_spc.c | 20 + > include/scsi/scsi.h | 1 + > include/target/target_core_base.h | 18 > 8 files changed, 209 insertions(+), 4 deletions(-) > > diff --git a/drivers/target/target_core_alua.c > b/drivers/target/target_core_alua.c > index 166bee6..8f66146 100644 > --- a/drivers/target/target_core_alua.c > +++ b/drivers/target/target_core_alua.c > @@ -56,6 +56,75 @@ static LIST_HEAD(lu_gps_list); > struct t10_alua_lu_gp *default_lu_gp; > > /* > + * REPORT REFERRALS > + * > + * See sbc3r35 section 5.23 > + */ > +sense_reason_t > +target_emulate_report_referrals(struct se_cmd *cmd) > +{ > + struct se_device *dev = cmd->se_dev; > + struct t10_alua_lba_map *map; > + struct t10_alua_lba_map_member *map_mem; > + unsigned char *buf; > + u32 rd_len = 0, off; > + > + if (cmd->data_length < 4) { > + pr_warn("REPORT REFERRALS allocation length %u too" > + " small\n", cmd->data_length); > + return TCM_INVALID_CDB_FIELD; > + } > + > + buf = transport_kmap_data_sg(cmd); > + if (!buf) > + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; > + > + off = 4; > + spin_lock(&dev->t10_alua.lba_map_lock); > + if (list_empty(&dev->t10_alua.lba_map_list)) { > + spin_unlock(&dev->t10_alua.lba_map_lock); > + transport_kunmap_data_sg(cmd); > + > + return TCM_UNSUPPORTED_SCSI_OPCODE; > + } > + > + list_for_each_entry(map, &dev->t10_alua.lba_map_list, > + lba_map_list) { > + int desc_num = off + 3; > + int pg_num; > + > + off += 4; > + put_unaligned_be64(map->lba_map_first_lba, &buf[off]); > + off += 8; > + put_unaligned_be64(map->lba_map_last_lba, &buf[off]); > + off += 8; > + rd_len += 20; > + pg_num = 0; > + list_for_each_entry(map_mem, &map->lba_map_mem_list, > + lba_map_mem_list) { > + buf[off++] = map_mem->lba_map_mem_alua_state & 0x0f; > + off++; > + buf[off++] = (map_mem->lba_map_mem_alua_pg_id >> 8) & > 0xff; > + buf[off++] = (map_mem->lba_map_mem_alua_pg_id & 0xff); > + rd_len += 4; > + pg_num++; > + } > + buf[desc_num] = pg_num; > + } > + spin_unlock(&dev->t10_alua.lba_map_lock); > + For both of these list walks, there needs to be a check against offset vs. ->data_length to know when the available payload length has been exhausted.. > + /* > + * Set the RETURN DATA LENGTH set in the header of the DataIN Payload > + */ > + put_unaligned_be16(rd_len, &buf[2]); > + > + transport_kunmap_data_sg(cmd); > + > + target_complete_cmd(cmd, GOOD); > + return 0; > +} > + > +/* > * REPORT_TARGET_PORT_GROUPS > * > * See spc4r17 section 6.27 > @@ -389,6 +458,80 @@ static inline int core_alua_state_nonoptimized( > return 0; > } > > +static inline int core_alua_state_lba_dependent( > + struct se_cmd *cmd, > + struct t10_alua_tg_pt_gp *tg_pt_gp, > + u8 *alua_ascq) > +{ > + struct se_device *dev = cmd->se_dev; > + u32 segment_size, segment_mult, sectors; > + u64 lba; > + > + /* Only need to check for cdb actually containing LBAs */ > + if (!cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) > + return 0; > + > + spin_lock(&dev->t10_alua.lba_map_lock); > + segment_size = dev->t10_alua.lba_map_segment_size; > + segment_mult = dev->t10_alua.lba_map_segment_multiplier; > + sectors = cmd->data_length / dev->dev_attrib.block_size; > + > + lba = cmd->t_task_lba; > + while (lba < cmd->t_task_lba + sectors) { > + struct t10_alua_lba_map *cur_map = NULL, *map; > + struct t10_alua_lba_map_member *map_mem; > + > + list_for_each_entry(map, &dev->t10_alua.lba_map_list, > + lba_map_list) { > + u64 start_lba, last_lba; > + u64 first_lba = map->lba_map_first_lba; > + > + if (segment_mult) { > + start_lba = lba % (segment_size * segment_mult); > + last_lba = first_lba + segment_size - 1; > + if (start_lba >= first_lba && > + start_lba <= last_lba) { > +
Re: [PATCH 3/3] Fix device detection issues with mvsas driver
Hi Xiang, Can you please take a look at the attached patch and ack it? Thanks, Praveen On 10/16/2013 02:45 PM, James Bottomley wrote: On Tue, 2013-10-15 at 19:40 -0700, Praveen Murali wrote: Yes, I checked that today and was meaning to ask you about it. :) Ideally, I need someone from Marvell to ack it ... can you prod them? Thanks, James >From 6ad9cf691f9d11e8c6de332efc35bd945c0f2840 Mon Sep 17 00:00:00 2001 From: Praveen Murali Date: Thu, 21 Jun 2012 09:57:03 -0700 Subject: [PATCH v2] Fix mvsas SATA disk detection issues I am using the Marvell SAS HBA (MV64460/64461/64462 System Controller, Revision B (rev 01)), on a system running Ubuntu 12.04 stock kernel. And i am seeing some drive detection issues with SATA drives, mostly during hotplugging the drives; the issue gets exaggerated when we keep removing and plugging in drives. >From dmesg, after starting the LibATA debugs, it looks like the ata_eh_revalidate_and_attach fails because ata_dev_read_id fails to get the IDENTIFY command response. I see "both IDENTIFYs aborted, assuming NODEV" for all these drives that go undetected. At this point, if I unload and reload the mvsas driver, these drives detect fine. So, I hooked up a SATA analyzer between the HBA and one of the drives, and restarted the test. From what I can see, even though the drive responds to the IDENTIFY command, the upper layer detects an error and discards the response. On further debugging it was evident that the error was being detected in the FIS. After going thru the mvsas driver, I see that during init the driver allocates a DMA area for an FIS pool (for as many as 33 FIS's) and initializes it to 0. And each ATA command is allocated a FIS area from this pool during the command prep; but its never cleared. The fix is to cleanup and prepare the FIS index before issuing the ATA command (during prep: mvs_task_prep_ata). --- drivers/scsi/mvsas/mv_sas.c |5 + 1 file changed, 5 insertions(+) diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c index a4884a5..73d9816 100644 --- a/drivers/scsi/mvsas/mv_sas.c +++ b/drivers/scsi/mvsas/mv_sas.c @@ -458,6 +458,11 @@ static int mvs_task_prep_ata(struct mvs_info *mvi, mvi_dev->device_id); return -EBUSY; } + + /* cleanup and prepare the allocated FIS index */ + memset( SATA_RECEIVED_D2H_FIS(mvi_dev->taskfileset), 0, +sizeof(struct dev_to_host_fis) ); + slot = &mvi->slot_info[tag]; slot->tx = mvi->tx_prod; del_q = TXQ_MODE_I | tag | -- 1.7.10
How are you doing.
Dear friend I am Mr.Axel Brice a banker from one of the international bank here in my country. Although the world is spherical and hard place to met people because you don't know who to trust or believe, but I have developed my trust to you to confide this confidential business proposal. 4 years ago, most of the African Politicians used our bank to launder fund to overseas through the help of their Political advisers, I find out what was going because these days some of the fund where stock for politicians, I was able to divert ($15.2M) to an escrow account that belong to unknown person. So i will like you to act as the depositor of the fund because the bank do not know the owner of the fund and also the claim is legal as i have make all the good arrangement to transfer the fund to foreign account. Thanks Mr. Axel Brice -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 00/11] target_core_mod: ALUA updates
On Wed, 2013-10-16 at 09:20 +0200, Hannes Reinecke wrote: > Hi Nic, > > here are some updates to TCM ALUA handling. Apart from some > minor fixes and spellchecks the main features are: > - Make supported states configurable: > We should make the list of supported ALUA states configurable, > as some setups would possibly like to support a small subset > of ALUA states only. > - Asynchronous transitioning: I've switched 'transitioning' > handling to use a workqueue, that should allow us to simulate > asynchronous transitioning modes. IE TCM should now be capable > of handling requests while in transitioning, and properly terminate > these with the correct sense code. > - Include target device descriptor in VPD page 83 > For the ALUA device handler we'd need to identify the target device > where a given target port belongs to. So include the respective > values in the VPD page. > > Hannes Reinecke (11): > target core: rename (ex,im)plict -> (ex,im)plicit > target_core_alua: Store supported ALUA states > target_core_alua: Make supported states configurable > target_core_alua: Rename ALUA_ACCESS_STATE_OPTIMIZED > target_core_alua: spellcheck > target_core_alua: Validate ALUA state transition > target_core_alua: Allocate ALUA metadata on demand > target_core_alua: store old and pending ALUA state > target_core_alua: Use workqueue for ALUA transitioning > target_core: simplify scsi_name_len calculation > target_core_spc: Include target device descriptor in VPD page 83 > Hey Hannes, It looks like Patches #10 && #11 did not make it to the list. Care to address the minor comments on the others and repost a -v2 with the missing ones..? --nab -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 09/11] target_core_alua: Use workqueue for ALUA transitioning
On Wed, 2013-10-16 at 09:20 +0200, Hannes Reinecke wrote: > Use a workqueue for processing ALUA state transitions; this allows > us to process implicit delay properly. > > Signed-off-by: Hannes Reinecke > --- > drivers/target/target_core_alua.c | 174 > +++--- > include/target/target_core_base.h | 4 + > 2 files changed, 128 insertions(+), 50 deletions(-) > > +static int core_alua_do_transition_tg_pt( > + struct t10_alua_tg_pt_gp *tg_pt_gp, > + int new_state, > + int explicit) > +{ > + struct se_device *dev = tg_pt_gp->tg_pt_gp_dev; > + DECLARE_COMPLETION_ONSTACK(wait); > + > + /* Nothing to be done here */ > + if (atomic_read(&tg_pt_gp->tg_pt_gp_alua_access_state) == new_state) > + return 0; > + > + if (new_state == ALUA_ACCESS_STATE_TRANSITION) > + return -EAGAIN; > + > + /* > + * Flush any pending transitions > + */ > + if (!explicit && tg_pt_gp->tg_pt_gp_implicit_trans_secs && > + atomic_read(&tg_pt_gp->tg_pt_gp_alua_access_state) == > + ALUA_ACCESS_STATE_TRANSITION) { > + /* Just in case */ > + tg_pt_gp->tg_pt_gp_alua_pending_state = new_state; > + tg_pt_gp->tg_pt_gp_transition_complete = &wait; > + flush_delayed_work(&tg_pt_gp->tg_pt_gp_transition_work); > + wait_for_completion(&wait); > + tg_pt_gp->tg_pt_gp_transition_complete = NULL; > + return 0; > + } > + > + /* > + * Save the old primary ALUA access state, and set the current state > + * to ALUA_ACCESS_STATE_TRANSITION. > + */ > + tg_pt_gp->tg_pt_gp_alua_previous_state = > + atomic_read(&tg_pt_gp->tg_pt_gp_alua_access_state); > + tg_pt_gp->tg_pt_gp_alua_pending_state = new_state; > + > + atomic_set(&tg_pt_gp->tg_pt_gp_alua_access_state, > + ALUA_ACCESS_STATE_TRANSITION); > + tg_pt_gp->tg_pt_gp_alua_access_status = (explicit) ? > + ALUA_STATUS_ALTERED_BY_EXPLICIT_STPG : > + ALUA_STATUS_ALTERED_BY_IMPLICIT_ALUA; > + > + /* > + * Check for the optional ALUA primary state transition delay > + */ > + if (tg_pt_gp->tg_pt_gp_trans_delay_msecs != 0) > + msleep_interruptible(tg_pt_gp->tg_pt_gp_trans_delay_msecs); > + > + /* > + * Take a reference for workqueue item > + */ > + spin_lock(&dev->t10_alua.tg_pt_gps_lock); > + atomic_inc(&tg_pt_gp->tg_pt_gp_ref_cnt); > + smp_mb__after_atomic_inc(); > + spin_unlock(&dev->t10_alua.tg_pt_gps_lock); > + > + if (!explicit && tg_pt_gp->tg_pt_gp_implicit_trans_secs) { > + unsigned long transition_tmo; > + > + transition_tmo = tg_pt_gp->tg_pt_gp_implicit_trans_secs * HZ; > + queue_delayed_work(tg_pt_gp->tg_pt_gp_dev->tmr_wq, > +&tg_pt_gp->tg_pt_gp_transition_work, > +transition_tmo); > + } else { > + tg_pt_gp->tg_pt_gp_transition_complete = &wait; > + queue_delayed_work(tg_pt_gp->tg_pt_gp_dev->tmr_wq, > +&tg_pt_gp->tg_pt_gp_transition_work, 0); > + wait_for_completion(&wait); > + tg_pt_gp->tg_pt_gp_transition_complete = NULL; > + } Mmm, the trans_delay_msecs delay seems a bit out of place now.. How about dropping it's usage with msleep_interruptible() above, and instead combining it with the delay passed into queue_delayed_work()..? --nab -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Help us complete this charity project, reply for detail!!!
-- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 3/3] Fix device detection issues with mvsas driver
On Tue, 2013-10-15 at 19:40 -0700, Praveen Murali wrote: > Yes, I checked that today and was meaning to ask you about it. :) Ideally, I need someone from Marvell to ack it ... can you prod them? Thanks, James -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH][SCSI] megaraid_sas: Fix synchronization problem between sysPD IO path and AEN path
On Wed, 2013-10-16 at 17:04 +0530, sumit.sax...@lsi.com wrote: > There is syncronization problem between sysPD IO path and AEN path. Driver > maintains instance->pd_list[] array, which will get updated(by calling > function megasas_get_pd_list[]), whenever any of below events occurs- > > MR_EVT_PD_INSERTED > MR_EVT_PD_REMOVED > MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED > MR_EVT_FOREIGN_CFG_IMPORTED > > At same time running sysPD IO will be accessing the same array > instance->pd_list[], which is getting updated in AEN path, because > of this IO may not get correct PD info from instance->pd_list[] array. > > Signed-off-by: Adam Radford > Signed-off-by: Sumit Saxena Explain the signoff chain: is this a joinly authored patch? James -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 07/11] target_core_alua: Allocate ALUA metadata on demand
On Wed, 2013-10-16 at 09:20 +0200, Hannes Reinecke wrote: > We should only allocate ALUA metadata if we're actually going > to write them. > > Signed-off-by: Hannes Reinecke > --- > drivers/target/target_core_alua.c | 70 > +-- > drivers/target/target_core_alua.h | 3 ++ > include/target/target_core_base.h | 3 -- > 3 files changed, 34 insertions(+), 42 deletions(-) > Looks reasonable to me.. --nab > diff --git a/drivers/target/target_core_alua.c > b/drivers/target/target_core_alua.c > index a420778..b1d08bf 100644 > --- a/drivers/target/target_core_alua.c > +++ b/drivers/target/target_core_alua.c > @@ -762,16 +762,22 @@ static int core_alua_write_tpg_metadata( > */ > static int core_alua_update_tpg_primary_metadata( > struct t10_alua_tg_pt_gp *tg_pt_gp, > - int primary_state, > - unsigned char *md_buf) > + int primary_state) > { > + unsigned char *md_buf; > struct t10_wwn *wwn = &tg_pt_gp->tg_pt_gp_dev->t10_wwn; > char path[ALUA_METADATA_PATH_LEN]; > - int len; > + int len, rc; > + > + md_buf = kzalloc(ALUA_MD_BUF_LEN, GFP_KERNEL); > + if (!md_buf) { > + pr_err("Unable to allocate buf for ALUA metadata\n"); > + return -ENOMEM; > + } > > memset(path, 0, ALUA_METADATA_PATH_LEN); > > - len = snprintf(md_buf, tg_pt_gp->tg_pt_gp_md_buf_len, > + len = snprintf(md_buf, ALUA_MD_BUF_LEN, > "tg_pt_gp_id=%hu\n" > "alua_access_state=0x%02x\n" > "alua_access_status=0x%02x\n", > @@ -782,14 +788,15 @@ static int core_alua_update_tpg_primary_metadata( > "/var/target/alua/tpgs_%s/%s", &wwn->unit_serial[0], > config_item_name(&tg_pt_gp->tg_pt_gp_group.cg_item)); > > - return core_alua_write_tpg_metadata(path, md_buf, len); > + rc = core_alua_write_tpg_metadata(path, md_buf, len); > + kfree(md_buf); > + return rc; > } > > static int core_alua_do_transition_tg_pt( > struct t10_alua_tg_pt_gp *tg_pt_gp, > struct se_port *l_port, > struct se_node_acl *nacl, > - unsigned char *md_buf, > int new_state, > int explicit) > { > @@ -877,8 +884,7 @@ static int core_alua_do_transition_tg_pt( >*/ > if (tg_pt_gp->tg_pt_gp_write_metadata) { > mutex_lock(&tg_pt_gp->tg_pt_gp_md_mutex); > - core_alua_update_tpg_primary_metadata(tg_pt_gp, > - new_state, md_buf); > + core_alua_update_tpg_primary_metadata(tg_pt_gp, new_state); > mutex_unlock(&tg_pt_gp->tg_pt_gp_md_mutex); > } > /* > @@ -909,19 +915,12 @@ int core_alua_do_port_transition( > struct t10_alua_lu_gp *lu_gp; > struct t10_alua_lu_gp_member *lu_gp_mem, *local_lu_gp_mem; > struct t10_alua_tg_pt_gp *tg_pt_gp; > - unsigned char *md_buf; > int primary, valid_states; > > valid_states = l_tg_pt_gp->tg_pt_gp_alua_supported_states; > if (core_alua_check_transition(new_state, valid_states, &primary) != 0) > return -EINVAL; > > - md_buf = kzalloc(l_tg_pt_gp->tg_pt_gp_md_buf_len, GFP_KERNEL); > - if (!md_buf) { > - pr_err("Unable to allocate buf for ALUA metadata\n"); > - return -ENOMEM; > - } > - > local_lu_gp_mem = l_dev->dev_alua_lu_gp_mem; > spin_lock(&local_lu_gp_mem->lu_gp_mem_lock); > lu_gp = local_lu_gp_mem->lu_gp; > @@ -939,10 +938,9 @@ int core_alua_do_port_transition( >* success. >*/ > core_alua_do_transition_tg_pt(l_tg_pt_gp, l_port, l_nacl, > - md_buf, new_state, explicit); > + new_state, explicit); > atomic_dec(&lu_gp->lu_gp_ref_cnt); > smp_mb__after_atomic_dec(); > - kfree(md_buf); > return 0; > } > /* > @@ -992,7 +990,7 @@ int core_alua_do_port_transition( >* success. >*/ > core_alua_do_transition_tg_pt(tg_pt_gp, port, > - nacl, md_buf, new_state, explicit); > + nacl, new_state, explicit); > > spin_lock(&dev->t10_alua.tg_pt_gps_lock); > atomic_dec(&tg_pt_gp->tg_pt_gp_ref_cnt); > @@ -1014,7 +1012,6 @@ int core_alua_do_port_transition( > > atomic_dec(&lu_gp->lu_gp_ref_cnt); > smp_mb__after_atomic_dec(); > - kfree(md_buf); > return 0; > } > > @@ -1023,13 +1020,18 @@ int core_alua_do_port_transition( > */ > static int core_alua_update_tpg_secondary_metadata( > struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, > - struct se_port *port, > - unsigned char *md_buf, > - u32 md_buf_len) > + struct se_port *port) > { > + unsigned char *md_buf; > struct se
Re: [PATCH 06/11] target_core_alua: Validate ALUA state transition
On Wed, 2013-10-16 at 09:20 +0200, Hannes Reinecke wrote: > As we now can modify the list of supported states we need to > validate the requested ALUA state when doing a state transition. > > Signed-off-by: Hannes Reinecke > --- Looks good. --nab > drivers/target/target_core_alua.c | 85 > ++- > 1 file changed, 56 insertions(+), 29 deletions(-) > > diff --git a/drivers/target/target_core_alua.c > b/drivers/target/target_core_alua.c > index a16115e..a420778 100644 > --- a/drivers/target/target_core_alua.c > +++ b/drivers/target/target_core_alua.c > @@ -41,7 +41,8 @@ > #include "target_core_alua.h" > #include "target_core_ua.h" > > -static sense_reason_t core_alua_check_transition(int state, int *primary); > +static sense_reason_t core_alua_check_transition(int state, int valid, > + int *primary); > static int core_alua_set_tg_pt_secondary_state( > struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, > struct se_port *port, int explicit, int offline); > @@ -210,7 +211,7 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd) > unsigned char *ptr; > sense_reason_t rc = TCM_NO_SENSE; > u32 len = 4; /* Skip over RESERVED area in header */ > - int alua_access_state, primary = 0; > + int alua_access_state, primary = 0, valid_states; > u16 tg_pt_id, rtpi; > > if (!l_port) > @@ -252,6 +253,7 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd) > rc = TCM_UNSUPPORTED_SCSI_OPCODE; > goto out; > } > + valid_states = l_tg_pt_gp->tg_pt_gp_alua_supported_states; > > ptr = &buf[4]; /* Skip over RESERVED area in header */ > > @@ -263,7 +265,8 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd) >* the state is a primary or secondary target port asymmetric >* access state. >*/ > - rc = core_alua_check_transition(alua_access_state, &primary); > + rc = core_alua_check_transition(alua_access_state, > + valid_states, &primary); > if (rc) { > /* >* If the SET TARGET PORT GROUPS attempts to establish > @@ -614,21 +617,57 @@ out: > return 0; > } > > +static char *core_alua_dump_state(int state) > +{ > + switch (state) { > + case ALUA_ACCESS_STATE_ACTIVE_OPTIMIZED: > + return "Active/Optimized"; > + case ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED: > + return "Active/NonOptimized"; > + case ALUA_ACCESS_STATE_STANDBY: > + return "Standby"; > + case ALUA_ACCESS_STATE_UNAVAILABLE: > + return "Unavailable"; > + case ALUA_ACCESS_STATE_OFFLINE: > + return "Offline"; > + case ALUA_ACCESS_STATE_TRANSITION: > + return "Transitioning"; > + default: > + return "Unknown"; > + } > + > + return NULL; > +} > + > /* > * Check implicit and explicit ALUA state change request. > */ > static sense_reason_t > -core_alua_check_transition(int state, int *primary) > +core_alua_check_transition(int state, int valid, int *primary) > { > + /* > + * OPTIMIZED, NON-OPTIMIZED, STANDBY and UNAVAILABLE are > + * defined as primary target port asymmetric access states. > + */ > switch (state) { > case ALUA_ACCESS_STATE_ACTIVE_OPTIMIZED: > + if (!(valid & ALUA_AO_SUP)) > + goto not_supported; > + *primary = 1; > + break; > case ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED: > + if (!(valid & ALUA_AN_SUP)) > + goto not_supported; > + *primary = 1; > + break; > case ALUA_ACCESS_STATE_STANDBY: > + if (!(valid & ALUA_S_SUP)) > + goto not_supported; > + *primary = 1; > + break; > case ALUA_ACCESS_STATE_UNAVAILABLE: > - /* > - * OPTIMIZED, NON-OPTIMIZED, STANDBY and UNAVAILABLE are > - * defined as primary target port asymmetric access states. > - */ > + if (!(valid & ALUA_U_SUP)) > + goto not_supported; > *primary = 1; > break; > case ALUA_ACCESS_STATE_OFFLINE: > @@ -636,6 +675,8 @@ core_alua_check_transition(int state, int *primary) >* OFFLINE state is defined as a secondary target port >* asymmetric access state. >*/ > + if (!(valid & ALUA_O_SUP)) > + goto not_supported; > *primary = 0; > break; > default: > @@ -644,26 +685,11 @@ core_alua_check_transition(int state, int *primary) > } > > return 0; > -} > > -static char *core_alua_dump_state(int state) > -{ > - switch (state) { > - cas
Re: [PATCH 03/11] target_core_alua: Make supported states configurable
On Wed, 2013-10-16 at 09:20 +0200, Hannes Reinecke wrote: > Signed-off-by: Hannes Reinecke > --- > drivers/target/target_core_configfs.c | 50 > +++ > 1 file changed, 50 insertions(+) > > diff --git a/drivers/target/target_core_configfs.c > b/drivers/target/target_core_configfs.c > index d4c28a3..53e9e00 100644 > --- a/drivers/target/target_core_configfs.c > +++ b/drivers/target/target_core_configfs.c > @@ -2131,6 +2131,55 @@ static ssize_t > target_core_alua_tg_pt_gp_store_attr_alua_access_type( > SE_DEV_ALUA_TG_PT_ATTR(alua_access_type, S_IRUGO | S_IWUSR); > > /* > + * alua_supported_states > + */ > +static ssize_t target_core_alua_tg_pt_gp_show_attr_alua_supported_states( > + struct t10_alua_tg_pt_gp *tg_pt_gp, > + char *page) > +{ > + return sprintf(page, "%02x\n", > + tg_pt_gp->tg_pt_gp_alua_supported_states); > +} > + > +static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_supported_states( > + struct t10_alua_tg_pt_gp *tg_pt_gp, > + const char *page, > + size_t count) > +{ > + unsigned long tmp; > + int new_states, valid_states, ret; > + > + if (!tg_pt_gp->tg_pt_gp_valid_id) { > + pr_err("Unable to do set supported ALUA states on non" > + " valid tg_pt_gp ID: %hu\n", > + tg_pt_gp->tg_pt_gp_valid_id); > + return -EINVAL; > + } > + > + ret = strict_strtoul(page, 0, &tmp); > + if (ret < 0) { > + pr_err("Unable to extract new supported ALUA states" > + " from %s\n", page); > + return -EINVAL; > + } > + new_states = (int)tmp; > + valid_states = ALUA_T_SUP | ALUA_O_SUP | ALUA_LBD_SUP | \ > + ALUA_U_SUP | ALUA_S_SUP | ALUA_AN_SUP | ALUA_AO_SUP; > + > + > + if (new_states & ~valid_states) { > + pr_err("Illegal supported ALUA states: 0x%02x\n", > + new_states); > + return -EINVAL; > + } > + > + tg_pt_gp->tg_pt_gp_alua_supported_states = new_states; > + return count; > +} > + > +SE_DEV_ALUA_TG_PT_ATTR(alua_supported_states, S_IRUGO | S_IWUSR); > + > +/* > * alua_write_metadata > */ > static ssize_t target_core_alua_tg_pt_gp_show_attr_alua_write_metadata( > @@ -2350,6 +2399,7 @@ static struct configfs_attribute > *target_core_alua_tg_pt_gp_attrs[] = { > &target_core_alua_tg_pt_gp_alua_access_state.attr, > &target_core_alua_tg_pt_gp_alua_access_status.attr, > &target_core_alua_tg_pt_gp_alua_access_type.attr, > + &target_core_alua_tg_pt_gp_alua_supported_states.attr, > &target_core_alua_tg_pt_gp_alua_write_metadata.attr, > &target_core_alua_tg_pt_gp_nonop_delay_msecs.attr, > &target_core_alua_tg_pt_gp_trans_delay_msecs.attr, I'm thinking this might be better served by individual attributes representing the seven supported ALUA states, instead of a single attribute representing them all.. That would certainly make it easier for userspace to manipulate.. --nab -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 02/11] target_core_alua: Store supported ALUA states
On Wed, 2013-10-16 at 09:20 +0200, Hannes Reinecke wrote: > The supported ALUA states might be different for individual > devices, so store it in a separate field. > > Signed-off-by: Hannes Reinecke > --- > drivers/target/target_core_alua.c | 14 -- > drivers/target/target_core_alua.h | 11 +++ > include/target/target_core_base.h | 1 + > 3 files changed, 20 insertions(+), 6 deletions(-) > > diff --git a/drivers/target/target_core_alua.c > b/drivers/target/target_core_alua.c > index 8297d37..255e83c 100644 > --- a/drivers/target/target_core_alua.c > +++ b/drivers/target/target_core_alua.c > @@ -117,12 +117,7 @@ target_emulate_report_target_port_groups(struct se_cmd > *cmd) > /* >* Set supported ASYMMETRIC ACCESS State bits >*/ > - buf[off] = 0x80; /* T_SUP */ > - buf[off] |= 0x40; /* O_SUP */ > - buf[off] |= 0x8; /* U_SUP */ > - buf[off] |= 0x4; /* S_SUP */ > - buf[off] |= 0x2; /* AN_SUP */ > - buf[off++] |= 0x1; /* AO_SUP */ > + buf[off++] |= tg_pt_gp->tg_pt_gp_alua_supported_states; > /* >* TARGET PORT GROUP >*/ > @@ -1367,6 +1362,13 @@ struct t10_alua_tg_pt_gp > *core_alua_allocate_tg_pt_gp(struct se_device *dev, > tg_pt_gp->tg_pt_gp_trans_delay_msecs = ALUA_DEFAULT_TRANS_DELAY_MSECS; > tg_pt_gp->tg_pt_gp_implicit_trans_secs = > ALUA_DEFAULT_IMPLICIT_TRANS_SECS; > > + /* > + * Enable all supported states > + */ > + tg_pt_gp->tg_pt_gp_alua_supported_states = > + ALUA_T_SUP | ALUA_O_SUP | \ > + ALUA_U_SUP | ALUA_S_SUP | ALUA_AN_SUP | ALUA_AO_SUP; > + > if (def_group) { > spin_lock(&dev->t10_alua.tg_pt_gps_lock); > tg_pt_gp->tg_pt_gp_id = > diff --git a/drivers/target/target_core_alua.h > b/drivers/target/target_core_alua.h > index 74cf0c0..e826a65 100644 > --- a/drivers/target/target_core_alua.h > +++ b/drivers/target/target_core_alua.h > @@ -23,6 +23,17 @@ > #define ALUA_ACCESS_STATE_TRANSITION 0xf > > /* > + * from spc4r36j section 6.37 Table 306 > + */ > +#define ALUA_T_SUP 0x80 > +#define ALUA_O_SUP 0x40 > +#define ALUA_LBD_SUP 0x10 > +#define ALUA_U_SUP 0x08 > +#define ALUA_S_SUP 0x04 > +#define ALUA_AN_SUP 0x02 > +#define ALUA_AO_SUP 0x01 > + > +/* How about making these the supported bits, TPGS mode, and ALUA access state definitions common between target_core_alua.c and scsi_dh_alua.c..? --nab -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 01/11] target core: rename (ex,im)plict -> (ex,im)plicit
On Wed, 2013-10-16 at 09:20 +0200, Hannes Reinecke wrote: > Signed-off-by: Hannes Reinecke > --- > drivers/target/target_core_alua.c | 110 > - > drivers/target/target_core_alua.h | 20 +++--- > drivers/target/target_core_configfs.c | 26 > drivers/target/target_core_device.c| 6 +- > drivers/target/target_core_file.c | 2 +- > drivers/target/target_core_pr.c| 24 +++ > drivers/target/target_core_spc.c | 6 +- > drivers/target/target_core_transport.c | 4 +- > drivers/target/target_core_ua.h| 2 +- > include/target/target_core_base.h | 2 +- > 10 files changed, 101 insertions(+), 101 deletions(-) > Applied to target-pending/for-next. Thanks Hannes! --nab -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 0/5] Updates for tcm_loop
On Wed, 2013-10-16 at 09:12 +0200, Hannes Reinecke wrote: > Hi Nic, > > here are some updates to tcm_loop I've done during ALUA testing. > I've implemented a 'transport_state' attribute to simulate > transport failure and added command abort callbacks. > > Hannes Reinecke (5): > tcm_loop: Check for valid hba in tcm_loop_drop_nexus() > tcm_loop: Implement transport offline > tcm_loop: separate out tcm_loop_issue_tmr > tcm_loop: TCQ and command abort support > tcm_loop: Implement target reset > > drivers/target/loopback/tcm_loop.c | 233 > +++-- > drivers/target/loopback/tcm_loop.h | 6 + > include/target/target_core_base.h | 1 + > 3 files changed, 204 insertions(+), 36 deletions(-) > Everything looks reasonable to me.. Applied to target-pending/for-next. Thanks Hannes! --nab -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] target: Return an error for WRITE SAME with ANCHOR==1
On Mon, 2013-10-14 at 15:49 -0700, Roland Dreier wrote: > From: Roland Dreier > > Per SBC-3, since we report ANC_SUP==0 in VPD page B2h, we need to return > an error (ILLEGAL REQUEST/INVALID FIELD IN CDB) for all WRITE SAME > requests with ANCHOR==1. > > Signed-off-by: Roland Dreier Applied to target-pending/master. Thanks Roland! --nab > --- > drivers/target/target_core_sbc.c | 5 + > 1 file changed, 5 insertions(+) > > diff --git a/drivers/target/target_core_sbc.c > b/drivers/target/target_core_sbc.c > index 4714c6f8da4b..d9b92b2c524d 100644 > --- a/drivers/target/target_core_sbc.c > +++ b/drivers/target/target_core_sbc.c > @@ -263,6 +263,11 @@ sbc_setup_write_same(struct se_cmd *cmd, unsigned char > *flags, struct sbc_ops *o > sectors, cmd->se_dev->dev_attrib.max_write_same_len); > return TCM_INVALID_CDB_FIELD; > } > + /* We always have ANC_SUP == 0 so setting ANCHOR is always an error */ > + if (flags[0] & 0x10) { > + pr_warn("WRITE SAME with ANCHOR not supported\n"); > + return TCM_INVALID_CDB_FIELD; > + } > /* >* Special case for WRITE_SAME w/ UNMAP=1 that ends up getting >* translated into block discard requests within backend code. -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
kernel cant access SATA adapter device
Hi, I've got a SATA adapter for a SD card in a Dell Poweredge R610. The BIOS can see and boot the sdcard, (to Windows, or using syslinux/extlinux), but when it hands over control to the Linux kernel, the kernel cannot access it. Here's an excerpt from dmesg: scsi 0:0:2:0: Direct-Access ATA FC-1307 SD to CF 1.1 PQ: 0 ANSI: 5 sd 0:0:2:0: Attached scsi generic sg3 type 0 mptsas: ioc0: mptsas_free_fw_event: kfree (fw_event=0x8801ab1ad8c0) sd 0:0:2:0: [sdc] Spinning up disk .not responding... sd 0:0:2:0: [sdc] READ CAPACITY(16) failed sd 0:0:2:0: [sdc] Result: hostbyte=DID_OK driverbyte=DRIVER_SENSE sd 0:0:2:0: [sdc] Sense Key : Not Ready [current] sd 0:0:2:0: [sdc] Add. Sense: Logical unit not ready, initializing command required sd 0:0:2:0: [sdc] READ CAPACITY failed sd 0:0:2:0: [sdc] Result: hostbyte=DID_OK driverbyte=DRIVER_SENSE sd 0:0:2:0: [sdc] Sense Key : Not Ready [current] sd 0:0:2:0: [sdc] Add. Sense: Logical unit not ready, initializing command required sd 0:0:2:0: [sdc] Test WP failed, assume Write Enabled sd 0:0:2:0: [sdc] Asking for cache data failed sd 0:0:2:0: [sdc] Assuming drive cache: write through After booting and running 'sdparm --command=start /dev/sdc' I can get a read capacity to work, but cannot access the drive (e.g. fdisk -l /dev/sdc). If I put the SD card in a USB adapter, it works, and I was able to access the SD card via the SD adapter in another machine. But our production machines are dell's, so I really want to get it working there. I've attached more complete debug info from booting and existing CentOS 6.4 install with the card installed, and a rdsosreport from an attempt to boot Fedora 20 Alpha. Any help or suggestions greatly appreciated. Robert -- Senior Software Engineer Parsons Government Services , National Security & Defense Division -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [Bug] 12.864681 BUG: lock held when returning to user space!
On Tue, 2013-10-08 at 09:45 -0400, Douglas Gilbert wrote: > On 13-10-08 02:44 AM, vaughan wrote: > > Hi Madper, > > > > CC to Douglas to get comments. > > I use the rw_semaphore o_sem to protect excl open, introduced in commit > > 15b06f9a02406e5460001db6d5af5c738cd3d4e7 since v3.12-rc1. > > Is it forbidden to do like that in kernel?... > > It appears you can not (allow sg_open() to hold a semaphore > then return to the user space). So you will need to do some > rework on that patch or revert it. OK, there being no reply on this, I'll do the revert ... that's all four patches, correct? James -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 1/3] scsi: Fix erratic device offline during EH
On Mon, 2013-09-02 at 13:58 +0200, Hannes Reinecke wrote: > Commit 18a4d0a22ed6c54b67af7718c305cd010f09ddf8 > (Handle disk devices which can not process medium access commands) > was introduced to offline any device which cannot process medium > access commands. > However, commit 3eef6257de48ff84a5d98ca533685df8a3beaeb8 > (Reduce error recovery time by reducing use of TURs) reduced > the number of TURs by sending it only on the first failing > command, which might or might not be a medium access command. > So in combination this results in an erratic device offlining > during EH; if the command where the TUR was sent upon happens > to be a medium access command the device will be set offline, > if not everything proceeds as normal. > > So instead of checking the EH command in the ->eh_action > callback we should rather call ->eh_action when we're > about to finish the command _and_ have sent a TUR previously. > This should then set the device offline as advertised. > > Cc: Martin K. Petersen > Cc: Ewan Milne > Signed-off-by: Hannes Reinecke > --- > drivers/scsi/scsi_error.c | 28 +++- > 1 file changed, 19 insertions(+), 9 deletions(-) > > diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c > index abf0916..c88cb7e 100644 > --- a/drivers/scsi/scsi_error.c > +++ b/drivers/scsi/scsi_error.c > @@ -941,12 +941,6 @@ retry: > > scsi_eh_restore_cmnd(scmd, &ses); > > - if (scmd->request->cmd_type != REQ_TYPE_BLOCK_PC) { > - struct scsi_driver *sdrv = scsi_cmd_to_driver(scmd); > - if (sdrv->eh_action) > - rtn = sdrv->eh_action(scmd, cmnd, cmnd_size, rtn); > - } > - > return rtn; > } > > @@ -964,6 +958,18 @@ static int scsi_request_sense(struct scsi_cmnd *scmd) > return scsi_send_eh_cmnd(scmd, NULL, 0, scmd->device->eh_timeout, ~0); > } > > +static int scsi_eh_action(struct scsi_cmnd *scmd, int rtn) > +{ > + static unsigned char tur_command[6] = {TEST_UNIT_READY, 0, 0, 0, 0, 0}; > + > + if (scmd->request->cmd_type != REQ_TYPE_BLOCK_PC) { > + struct scsi_driver *sdrv = scsi_cmd_to_driver(scmd); > + if (sdrv->eh_action) > + rtn = sdrv->eh_action(scmd, tur_command, 6, rtn); This is all a bit pointless. You've altered eh_action so it's always input an eh TUR command, so just eliminate the check of the eh command and assume it's a TUR in the implementation (i.e. fix up sd.c) Once that's done, I think the patch looks like the one below, is that OK? I still have qualms about the media access check because what can happen is that we abort, TUR succeeds then the next Media access command fails, we abort, TUR succeeds etc until the media access timeout goes off. The problem is that it never gets escalated to a reset which might fix the condition. However, this is beyond the scope of the current patch set. James --- diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 83e591b..aef80f1 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -923,12 +923,6 @@ retry: scsi_eh_restore_cmnd(scmd, &ses); - if (scmd->request->cmd_type != REQ_TYPE_BLOCK_PC) { - struct scsi_driver *sdrv = scsi_cmd_to_driver(scmd); - if (sdrv->eh_action) - rtn = sdrv->eh_action(scmd, cmnd, cmnd_size, rtn); - } - return rtn; } @@ -946,6 +940,16 @@ static int scsi_request_sense(struct scsi_cmnd *scmd) return scsi_send_eh_cmnd(scmd, NULL, 0, scmd->device->eh_timeout, ~0); } +static int scsi_eh_action(struct scsi_cmnd *scmd, int rtn) +{ + if (scmd->request->cmd_type != REQ_TYPE_BLOCK_PC) { + struct scsi_driver *sdrv = scsi_cmd_to_driver(scmd); + if (sdrv->eh_action) + rtn = sdrv->eh_action(scmd, rtn); + } + return rtn; +} + /** * scsi_eh_finish_cmd - Handle a cmd that eh is finished with. * @scmd: Original SCSI cmd that eh has finished. @@ -1094,7 +1098,9 @@ static int scsi_eh_test_devices(struct list_head *cmd_list, list_for_each_entry_safe(scmd, next, cmd_list, eh_entry) if (scmd->device == sdev) { - if (finish_cmds) + if (finish_cmds && + (try_stu || +scsi_eh_action(scmd, SUCCESS) == SUCCESS)) scsi_eh_finish_cmd(scmd, done_q); else list_move_tail(&scmd->eh_entry, work_q); @@ -1208,7 +1214,8 @@ static int scsi_eh_stu(struct Scsi_Host *shost, !scsi_eh_tur(stu_scmd)) { list_for_each_entry_safe(scmd, next, work_q, eh_entry) { - if (scmd-
Re: [PATCH 7/7] scsi: Add 'eh_deadline' to limit SCSI EH runtime
On Mon, 2013-07-01 at 08:50 +0200, Hannes Reinecke wrote: > This patchs adds an 'eh_deadline' sysfs attribute to the scsi > host which limits the overall runtime of the SCSI EH. > The 'eh_deadline' value is stored in the now obsolete field > 'resetting'. > When a command is failed the start time of the EH is stored > in 'last_reset'. If the overall runtime of the SCSI EH is longer > than last_reset + eh_deadline, the EH is short-circuited and > falls through to issue a host reset only. OK, so the specific problem with this one is that potentially it will spend all its time mucking about with aborts (which most often time out on non FC kit because of the issue problems) and then proceed to host reset, which mostly does nothing for failing devices. If you want to impose a deadline, then we need to spend only 50% of the time attempting aborts and the rest of the time escalating the resets. [...] > diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c > index f43de1e..84369f2 100644 > --- a/drivers/scsi/scsi_error.c > +++ b/drivers/scsi/scsi_error.c > @@ -89,6 +89,18 @@ void scsi_schedule_eh(struct Scsi_Host *shost) > } > EXPORT_SYMBOL_GPL(scsi_schedule_eh); > > +static int scsi_host_eh_past_deadline(struct Scsi_Host *shost) > +{ > + if (!shost->last_reset || !shost->eh_deadline) > + return 0; > + > + if (time_before(jiffies, > + shost->last_reset + shost->eh_deadline)) > + return 0; > + > + return 1; > +} > + What about instead: static int scsi_host_eh_past_deadline(struct Scsi_Host *shost, int percent) { if (!shost->last_reset || !shost->eh_deadline) return 0; if (time_before(jiffies, shost->last_reset + shost->eh_deadline * percent/100)) return 0; return 1; } which allows us to have if (scsi_host_eh_past_deadline(shost, 50)) { in scsi_eh_abort_cmds() if (scsi_host_eh_past_deadline(shost, 66) { in scsi_eh_bus_device_reset() say 83 in target reset, and 100 in bus reset. Thus ensuring we at least get a crack at the reset chain? James -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] drivers: scsi: lpfc: Fix typo on NULL assignment
Acked-by: James Smart -- james s On 10/15/2013 8:29 PM, Felipe Pena wrote: In the lpfc_ct_free_iocb function after freeing associated memory to the ctiocb->context3, the ctiocb->context1 is set to NULL instead of context3. Signed-off-by: Felipe Pena --- drivers/scsi/lpfc/lpfc_ct.c |2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index 02e8cd9..da61d8d 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -280,7 +280,7 @@ lpfc_ct_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *ctiocb) buf_ptr = (struct lpfc_dmabuf *) ctiocb->context3; lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys); kfree(buf_ptr); - ctiocb->context1 = NULL; + ctiocb->context3 = NULL; } lpfc_sli_release_iocbq(phba, ctiocb); return 0; -- 1.7.10.4 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: eSATA Drive Detection issues on mvsas
On 10/15/2013 06:11 PM, Dan Williams wrote: On Tue, Oct 15, 2013 at 5:15 PM, Praveen Murali wrote: Dan/James, Can you please take a look at this and let me know if I am at the right place? Or point me in the right direction? As I understand, this deost not look like an mvsas driver issue. Looks like a latent bug in libsas to me. Commit 110dd8f1 "[SCSI] libsas: fix scr_read/write users and update the libata documentation" looks like a compile fix when the build was broken by commit 9977126c "libata: add @is_cmd to ata_tf_to_fis()" where libata changed the interface for ata_tf_to_fis(). We were passing 0 for pmp prior to that and changed to 1 here, probably a typo intending 'is_cmd to always be 1. Somehow we have gotten away with is_cmd being 0? Does the following patch work for you: diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index 161c98efade9..d0fb99d5da95 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -211,7 +211,7 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc) qc->tf.nsect = 0; } - ata_tf_to_fis(&qc->tf, 1, 0, (u8*)&task->ata_task.fis); + ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, (u8*)&task->ata_task.fis); task->uldd_task = qc; if (ata_is_atapi(qc->tf.protocol)) { memcpy(task->ata_task.atapi_packet, qc->cdb, qc->dev->cdb_len); Hi Dan, I tested this patch and it works great! Thanks, Praveen That being said I don't think anybody has really checked out port-multiplier support on libsas, but we shouldn't be setting this bit by default. -- Dan On 10/14/2013 05:18 PM, Praveen Murali wrote: Hi, I have couple of external drives (Western Digital and Seagate) that have an eSATA interface. My Linux box with a Marvell HBA (9445) running Ubuntu 12.04 with 3.2.48 kernel doest not seem to detect the drive. I tried with the latest upstream kernel and it behaves the same. But both the drives detect fine if I enter the mvsas BIOS during bootup. So I have hooked up a SATA analyzer and this is what I found - When I tried to detect the drives in the mvsas BIOS, all the ATA commands that the bios issues have the port multiplier byte set to 0. - If I bootup my Linux system and then connect the drives, the first IDENTIFY command has the port multiplier set to 0 (this one is successful) and the subsequent IDENTIFY command has port multiplier set to 1 (this one fails). I assume the first IDENTIFY is coming from the BIOS, not Linux correct? - If I connect any other SATA drives I have to the HBA, all the ATA commands have port multiplier set to 1 but they detects and work fine. Just to rule out the port-multiplier possibility I changed the following line in drivers/scsi/libsas/sas_ata.c - fucntion sas_ata_qc_issue() ata_tf_to_fis(&qc->tf, 1, 0, (u8*)&task->ata_task.fis); to ata_tf_to_fis(&qc->tf, 0, 0, (u8*)&task->ata_task.fis); now all my drives seem to detect just fine. I believe, the eSATA interface on these external drives is a port multiplier, which is why the command fails. Also, the normal drives ignore this field thats why they work fine with port multiplier being set to either 0 or 1. Question(s): Are my above assumtions correct? If so, what is the reasoning behind setting the port multiplier to 1 by default in libsas layer? Thanks, Praveen -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: How to online remove an error scsi disk from the system?
On Fri, Feb 01, 2013 at 02:13:16PM +0800, Tao Ma wrote: > Hi All, > In our product system, we have several sata disks attached to one > machine. So when one of the disk fails, the jbd2(yes, we use ext4) will > hang forever and we will get something in /var/log/messages like below. > It seems to me that the io sent to the scsi layer is never returned back > with -EIO which is a little bit surprised for me(It should be a timeout > somewhere, right?). We have tried echo "offline" > > /sys/block/sdl/device/state, but it doesn't work. So is there any way > for us to let the scsi device returns all the io requests back with EIO > so that all the end_io can be called accordingly? Am I missing something > here? > > Thanks, > Tao > > > sd 0:0:11:0: attempting task abort! scmd(88180e900580) It seems that IO timeout cause HBA's driver to abort scmd, the aborted IO came back with scmd->result = DID_RESET << 16; with this result code the Middle layer of scsi will retry this IO. IO timeout again due to Bad disk so, this IO loop forever and never come back. might it is a bug of mpt2sas driver. > sd 0:0:11:0: [sdl] CDB: Write(10): 2a 00 0d ca e0 3f 00 04 00 00 > target0:0:11: handle(0x0015), sas_address(0x500e004aaa0b), phy(11) > target0:0:11: enclosure_logical_id(0x500e004aaa00), slot(11) > INFO: task jbd2/sdl1-8:4629 blocked for more than 120 seconds. > "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. > jbd2/sdl1-8 D 0 4629 2 0x > 88180aa79ae0 0046 88180aa79aa8 > 88007ce0fe40 00015f40 8818102c0638 8818102c0080 > 880a9184a100 8818102c0638 000105006028 0001 > Call Trace: > [] ? cpumask_next_and+0x25/0x40 > [] ? read_tsc+0x16/0x40 > [] ? ktime_get_ts+0xa9/0xe0 > [] ? read_tsc+0x16/0x40 > [] ? ktime_get_ts+0xa9/0xe0 > [] io_schedule+0x73/0xc0 > [] sync_page+0x38/0x50 > [] __wait_on_bit+0x5e/0x90 > [] ? sync_page+0x0/0x50 > [] wait_on_page_bit+0x75/0x80 > [] ? wake_bit_function+0x0/0x40 > [] ? pagevec_lookup_tag+0x27/0x40 > [] write_cache_pages+0x1d5/0x440 > [] ? __writepage+0x0/0x40 > [] generic_writepages+0x24/0x30 > [] jbd2_journal_commit_transaction+0x3e9/0x1490 [jbd2] > [] ? try_to_del_timer_sync+0x49/0xe0 > [] kjournald2+0xb4/0x220 [jbd2] > [] ? autoremove_wake_function+0x0/0x40 > [] ? kjournald2+0x0/0x220 [jbd2] > [] kthread+0x96/0xa0 > [] child_rip+0xa/0x20 > [] ? kthread+0x0/0xa0 > [] ? child_rip+0x0/0x20 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-scsi" in > the body of a message to majord...@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] drivers: scsi: lpfc: Remove useless casting in lpfc_init.c
Casting (void *) value returned by kzalloc is useless as mentioned in Documentation/CodingStyle, Chap 14. Signed-off-by: Geyslan G. Bem --- drivers/scsi/lpfc/lpfc_init.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 647f5bf..bc417d5 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -4733,9 +4733,8 @@ lpfc_sli_driver_resource_setup(struct lpfc_hba *phba) } if (!phba->sli.ring) - phba->sli.ring = (struct lpfc_sli_ring *) - kzalloc(LPFC_SLI3_MAX_RING * - sizeof(struct lpfc_sli_ring), GFP_KERNEL); + phba->sli.ring = kzalloc(LPFC_SLI3_MAX_RING * +sizeof(struct lpfc_sli_ring), GFP_KERNEL); if (!phba->sli.ring) return -ENOMEM; -- 1.8.4 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] drivers: scsi: Remove useless casting in hpsa.c
Casting (void *) value returned by kmalloc is useless as mentioned in Documentation/CodingStyle, Chap 14. Signed-off-by: Geyslan G. Bem --- drivers/scsi/hpsa.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 891c86b..896a57d 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3093,8 +3093,7 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp) return -EINVAL; if (!capable(CAP_SYS_RAWIO)) return -EPERM; - ioc = (BIG_IOCTL_Command_struct *) - kmalloc(sizeof(*ioc), GFP_KERNEL); + ioc = kmalloc(sizeof(*ioc), GFP_KERNEL); if (!ioc) { status = -ENOMEM; goto cleanup1; -- 1.8.4 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH][SCSI] megaraid_sas: Fix synchronization problem between sysPD IO path and AEN path
There is syncronization problem between sysPD IO path and AEN path. Driver maintains instance->pd_list[] array, which will get updated(by calling function megasas_get_pd_list[]), whenever any of below events occurs- MR_EVT_PD_INSERTED MR_EVT_PD_REMOVED MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED MR_EVT_FOREIGN_CFG_IMPORTED At same time running sysPD IO will be accessing the same array instance->pd_list[], which is getting updated in AEN path, because of this IO may not get correct PD info from instance->pd_list[] array. Signed-off-by: Adam Radford Signed-off-by: Sumit Saxena --- diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 0c73ba4..e9e543c 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -1531,6 +1531,7 @@ struct megasas_instance { struct megasas_register_set __iomem *reg_set; u32 *reply_post_host_index_addr[MR_MAX_MSIX_REG_ARRAY]; struct megasas_pd_list pd_list[MEGASAS_MAX_PD]; + struct megasas_pd_list local_pd_list[MEGASAS_MAX_PD]; u8 ld_ids[MEGASAS_MAX_LD_IDS]; s8 init_id; diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index e62ff02..83ebc75 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -3194,21 +3194,23 @@ megasas_get_pd_list(struct megasas_instance *instance) (le32_to_cpu(ci->count) < (MEGASAS_MAX_PD_CHANNELS * MEGASAS_MAX_DEV_PER_CHANNEL))) { - memset(instance->pd_list, 0, + memset(instance->local_pd_list, 0, MEGASAS_MAX_PD * sizeof(struct megasas_pd_list)); for (pd_index = 0; pd_index < le32_to_cpu(ci->count); pd_index++) { - instance->pd_list[le16_to_cpu(pd_addr->deviceId)].tid = + instance->local_pd_list[le16_to_cpu(pd_addr->deviceId)].tid = le16_to_cpu(pd_addr->deviceId); - instance->pd_list[le16_to_cpu(pd_addr->deviceId)].driveType = + instance->local_pd_list[le16_to_cpu(pd_addr->deviceId)].driveType = pd_addr->scsiDevType; - instance->pd_list[le16_to_cpu(pd_addr->deviceId)].driveState= + instance->local_pd_list[le16_to_cpu(pd_addr->deviceId)].driveState = MR_PD_STATE_SYSTEM; pd_addr++; } } + memcpy(instance->pd_list, instance->local_pd_list, + sizeof(instance->pd_list)); pci_free_consistent(instance->pdev, MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST), ci, ci_h); -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[Bug 63141] New: Linux Kernel will shows "Got wrong page" in kernel log when Linux kernel tries to send SCSI ModeSense command with Page code 0x08 (Caching Mode Page)
https://bugzilla.kernel.org/show_bug.cgi?id=63141 Bug ID: 63141 Summary: Linux Kernel will shows "Got wrong page" in kernel log when Linux kernel tries to send SCSI ModeSense command with Page code 0x08 (Caching Mode Page) Product: IO/Storage Version: 2.5 Kernel Version: 3.6.11 Hardware: All OS: Linux Tree: Mainline Status: NEW Severity: low Priority: P1 Component: SCSI Assignee: linux-scsi@vger.kernel.org Reporter: leoche...@gmail.com Regression: No Created attachment 111291 --> https://bugzilla.kernel.org/attachment.cgi?id=111291&action=edit SourceCodeComparsionBetween2.6.xAnd3.9.1 Reporter: Leo Chen (Li-Chung Chen) Report Date: 10/16/13 Issue Descrition: In Linux kernel 3.6.11, sd.c file, host calls sd_read_cache_type() function to read physical disk or volume cache type. This function works properly on most physical disks but will fail to read the cache type on LSI raid volume. The error message in Linux Kernel is "Got wrong page". However, the Linux kernel works properly in kernel 2.6.x. Suggestion: If we restore below codes from 2.6.x to 3.6.11 in sd.c,sd_read_cache_type()function, then the kernel won't report "got wrong page" in the log. /* Take headers and block descriptors into account */ len += data.header_length + data.block_descriptor_length; I also referenced the SPC-4(SCSI Primary Commands - 4) specification from T10 to check if it's LSI firmware problem to response the wrong parameter length to the host. According to the description in SPC below, it looks like LSI logical volume doesn't voilate the specification to response the MODE DATA LENGTH value to host. [SPC-4 Description about the Mode Parameter] When using the MODE SENSE command, the MODE DATA LENGTH field indicates the length in bytes of the following data that is available to be transferred. The mode data length does not include the number of bytes in the MODE DATA LENGTH field. [SPC-4 Description about the Mode Parameter] Therefore, I'd like to suggest the Linux Kernel to add the code above to make the kernel handle the cache reading properly. -- You are receiving this mail because: You are the assignee for the bug. -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 2/2] target_core_alua: Referrals configfs integration
Referrals need an LBA map, which needs to be kept consistent across all target port groups. So instead of tying the map to the target port groups I've implemented a single attribute containing the entire map. Signed-off-by: Hannes Reinecke --- drivers/target/target_core_alua.c | 101 +++ drivers/target/target_core_alua.h | 8 ++ drivers/target/target_core_configfs.c | 171 + drivers/target/target_core_device.c| 1 + drivers/target/target_core_transport.c | 28 +- 5 files changed, 308 insertions(+), 1 deletion(-) diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index 8f66146..9dd01ff 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -1340,6 +1340,107 @@ static int core_alua_set_tg_pt_secondary_state( return 0; } +struct t10_alua_lba_map * +core_alua_allocate_lba_map(struct list_head *list, + u64 first_lba, u64 last_lba) +{ + struct t10_alua_lba_map *lba_map; + + lba_map = kmem_cache_zalloc(t10_alua_lba_map_cache, GFP_KERNEL); + if (!lba_map) { + pr_err("Unable to allocate struct t10_alua_lba_map\n"); + return ERR_PTR(-ENOMEM); + } + INIT_LIST_HEAD(&lba_map->lba_map_mem_list); + lba_map->lba_map_first_lba = first_lba; + lba_map->lba_map_last_lba = last_lba; + + list_add_tail(&lba_map->lba_map_list, list); + return lba_map; +} + +int +core_alua_allocate_lba_map_mem(struct t10_alua_lba_map *lba_map, + int pg_id, int state) +{ + struct t10_alua_lba_map_member *lba_map_mem; + + list_for_each_entry(lba_map_mem, &lba_map->lba_map_mem_list, + lba_map_mem_list) { + if (lba_map_mem->lba_map_mem_alua_pg_id == pg_id) { + pr_err("Duplicate pg_id %d in lba_map\n", pg_id); + return -EINVAL; + } + } + + lba_map_mem = kmem_cache_zalloc(t10_alua_lba_map_mem_cache, GFP_KERNEL); + if (!lba_map_mem) { + pr_err("Unable to allocate struct t10_alua_lba_map_mem\n"); + return -ENOMEM; + } + lba_map_mem->lba_map_mem_alua_state = state; + lba_map_mem->lba_map_mem_alua_pg_id = pg_id; + + list_add_tail(&lba_map_mem->lba_map_mem_list, + &lba_map->lba_map_mem_list); + return 0; +} + +void +core_alua_free_lba_map(struct list_head *lba_list) +{ + struct t10_alua_lba_map *lba_map, *lba_map_tmp; + struct t10_alua_lba_map_member *lba_map_mem, *lba_map_mem_tmp; + + list_for_each_entry_safe(lba_map, lba_map_tmp, lba_list, +lba_map_list) { + list_for_each_entry_safe(lba_map_mem, lba_map_mem_tmp, +&lba_map->lba_map_mem_list, +lba_map_mem_list) { + list_del(&lba_map_mem->lba_map_mem_list); + kmem_cache_free(t10_alua_lba_map_mem_cache, + lba_map_mem); + } + list_del(&lba_map->lba_map_list); + kmem_cache_free(t10_alua_lba_map_cache, lba_map); + } +} + +void +core_alua_set_lba_map(struct se_device *dev, struct list_head *lba_map_list, + int segment_size, int segment_mult) +{ + struct list_head old_lba_map_list; + struct t10_alua_tg_pt_gp *tg_pt_gp; + int activate = 0, supported; + + INIT_LIST_HEAD(&old_lba_map_list); + spin_lock(&dev->t10_alua.lba_map_lock); + dev->t10_alua.lba_map_segment_size = segment_size; + dev->t10_alua.lba_map_segment_multiplier = segment_mult; + list_splice_init(&dev->t10_alua.lba_map_list, &old_lba_map_list); + if (lba_map_list) { + list_splice_init(lba_map_list, &dev->t10_alua.lba_map_list); + activate = 1; + } + spin_unlock(&dev->t10_alua.lba_map_lock); + spin_lock(&dev->t10_alua.tg_pt_gps_lock); + list_for_each_entry(tg_pt_gp, &dev->t10_alua.tg_pt_gps_list, + tg_pt_gp_list) { + + if (!tg_pt_gp->tg_pt_gp_valid_id) + continue; + supported = tg_pt_gp->tg_pt_gp_alua_supported_states; + if (activate) + supported |= ALUA_LBD_SUP; + else + supported &= ~ALUA_LBD_SUP; + tg_pt_gp->tg_pt_gp_alua_supported_states = supported; + } + spin_unlock(&dev->t10_alua.tg_pt_gps_lock); + core_alua_free_lba_map(&old_lba_map_list); +} + struct t10_alua_lu_gp * core_alua_allocate_lu_gp(const char *name, int def_group) { diff --git a/drivers/target/target_core_alua.h b/drivers/target/target_core_alua.h index 47950cd..0a7d65e 100644 --- a/drivers/target/target_core_alua.h +++ b/driv
[PATCH 1/2] target_core_alua: Referrals infrastructure
Add infrastructure for referrals. Signed-off-by: Hannes Reinecke --- drivers/target/target_core_alua.c | 151 ++ drivers/target/target_core_alua.h | 4 +- drivers/target/target_core_configfs.c | 12 ++- drivers/target/target_core_device.c | 2 + drivers/target/target_core_sbc.c | 5 +- drivers/target/target_core_spc.c | 20 + include/scsi/scsi.h | 1 + include/target/target_core_base.h | 18 8 files changed, 209 insertions(+), 4 deletions(-) diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index 166bee6..8f66146 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -56,6 +56,75 @@ static LIST_HEAD(lu_gps_list); struct t10_alua_lu_gp *default_lu_gp; /* + * REPORT REFERRALS + * + * See sbc3r35 section 5.23 + */ +sense_reason_t +target_emulate_report_referrals(struct se_cmd *cmd) +{ + struct se_device *dev = cmd->se_dev; + struct t10_alua_lba_map *map; + struct t10_alua_lba_map_member *map_mem; + unsigned char *buf; + u32 rd_len = 0, off; + + if (cmd->data_length < 4) { + pr_warn("REPORT REFERRALS allocation length %u too" + " small\n", cmd->data_length); + return TCM_INVALID_CDB_FIELD; + } + + buf = transport_kmap_data_sg(cmd); + if (!buf) + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + + off = 4; + spin_lock(&dev->t10_alua.lba_map_lock); + if (list_empty(&dev->t10_alua.lba_map_list)) { + spin_unlock(&dev->t10_alua.lba_map_lock); + transport_kunmap_data_sg(cmd); + + return TCM_UNSUPPORTED_SCSI_OPCODE; + } + + list_for_each_entry(map, &dev->t10_alua.lba_map_list, + lba_map_list) { + int desc_num = off + 3; + int pg_num; + + off += 4; + put_unaligned_be64(map->lba_map_first_lba, &buf[off]); + off += 8; + put_unaligned_be64(map->lba_map_last_lba, &buf[off]); + off += 8; + rd_len += 20; + pg_num = 0; + list_for_each_entry(map_mem, &map->lba_map_mem_list, + lba_map_mem_list) { + buf[off++] = map_mem->lba_map_mem_alua_state & 0x0f; + off++; + buf[off++] = (map_mem->lba_map_mem_alua_pg_id >> 8) & 0xff; + buf[off++] = (map_mem->lba_map_mem_alua_pg_id & 0xff); + rd_len += 4; + pg_num++; + } + buf[desc_num] = pg_num; + } + spin_unlock(&dev->t10_alua.lba_map_lock); + + /* +* Set the RETURN DATA LENGTH set in the header of the DataIN Payload +*/ + put_unaligned_be16(rd_len, &buf[2]); + + transport_kunmap_data_sg(cmd); + + target_complete_cmd(cmd, GOOD); + return 0; +} + +/* * REPORT_TARGET_PORT_GROUPS * * See spc4r17 section 6.27 @@ -389,6 +458,80 @@ static inline int core_alua_state_nonoptimized( return 0; } +static inline int core_alua_state_lba_dependent( + struct se_cmd *cmd, + struct t10_alua_tg_pt_gp *tg_pt_gp, + u8 *alua_ascq) +{ + struct se_device *dev = cmd->se_dev; + u32 segment_size, segment_mult, sectors; + u64 lba; + + /* Only need to check for cdb actually containing LBAs */ + if (!cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) + return 0; + + spin_lock(&dev->t10_alua.lba_map_lock); + segment_size = dev->t10_alua.lba_map_segment_size; + segment_mult = dev->t10_alua.lba_map_segment_multiplier; + sectors = cmd->data_length / dev->dev_attrib.block_size; + + lba = cmd->t_task_lba; + while (lba < cmd->t_task_lba + sectors) { + struct t10_alua_lba_map *cur_map = NULL, *map; + struct t10_alua_lba_map_member *map_mem; + + list_for_each_entry(map, &dev->t10_alua.lba_map_list, + lba_map_list) { + u64 start_lba, last_lba; + u64 first_lba = map->lba_map_first_lba; + + if (segment_mult) { + start_lba = lba % (segment_size * segment_mult); + last_lba = first_lba + segment_size - 1; + if (start_lba >= first_lba && + start_lba <= last_lba) { + lba += segment_size; + cur_map = map; + break; + } + } else { + last_lba = map->lba_map_last_lba; + if (lba >= first_lba &&
[PATCH 0/2] TCM Referrals support
Hi Nic, I've finally bitten the bullet and implemented referrals support for TCM. It has been on my to-do list for a long time, but finally I've gotten around to actually _do_ anything about it. TCM now will enable referrals support when an appropriate map is being fed into 'lba_map'. Format there is: ... ... is the number of the first target port group, is a character denominating the ALUA access state: 'O' for 'Active/Optimized', 'A' for 'Active/Non-Optimized', 'S' for 'Standby', and 'U' for 'Unavailable'. For further details see SBC-3, Section 'Referrals'. Yes, I know, it's far from perfect and violates the 'one item per attribute' rule. But breaking this down into several attributes and ensure the update is done consistently _and_ atomically is beyond my configfs skills. So there. Hannes Reinecke (2): target_core_alua: Referrals infrastructure target_core_alua: Referrals configfs integration drivers/target/target_core_alua.c | 252 + drivers/target/target_core_alua.h | 12 +- drivers/target/target_core_configfs.c | 183 +++- drivers/target/target_core_device.c| 3 + drivers/target/target_core_sbc.c | 5 +- drivers/target/target_core_spc.c | 20 +++ drivers/target/target_core_transport.c | 28 +++- include/scsi/scsi.h| 1 + include/target/target_core_base.h | 18 +++ 9 files changed, 517 insertions(+), 5 deletions(-) -- 1.7.12.4 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: PROBLEM: special sense code asc,ascq=04h,0Ch abort scsi scan in the middle
On 10/16/2013 02:52 PM, Hannes Reinecke wrote: > But seeing that this approach raises quite some issues I've attached a > different patch. Vaughan, could you test with that, too? Should be > functionally equivalent to the previous one. Cheers, Hannes Of course. This one is more clear to express our intention than setting PQ 3 to break out. Vaughan -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 04/11] target_core_alua: Rename ALUA_ACCESS_STATE_OPTIMIZED
Rename ALUA_ACCESS_STATE_OPTMIZED to ALUA_ACCESS_STATE_OPTIMIZED. Signed-off-by: Hannes Reinecke --- drivers/target/target_core_alua.c | 10 +- drivers/target/target_core_alua.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index 255e83c..593de80 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -561,12 +561,12 @@ target_alua_state_check(struct se_cmd *cmd) nonop_delay_msecs = tg_pt_gp->tg_pt_gp_nonop_delay_msecs; spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); /* -* Process ALUA_ACCESS_STATE_ACTIVE_OPTMIZED in a separate conditional +* Process ALUA_ACCESS_STATE_ACTIVE_OPTIMIZED in a separate conditional * statement so the compiler knows explicitly to check this case first. * For the Optimized ALUA access state case, we want to process the * incoming fabric cmd ASAP.. */ - if (out_alua_state == ALUA_ACCESS_STATE_ACTIVE_OPTMIZED) + if (out_alua_state == ALUA_ACCESS_STATE_ACTIVE_OPTIMIZED) return 0; switch (out_alua_state) { @@ -621,7 +621,7 @@ static sense_reason_t core_alua_check_transition(int state, int *primary) { switch (state) { - case ALUA_ACCESS_STATE_ACTIVE_OPTMIZED: + case ALUA_ACCESS_STATE_ACTIVE_OPTIMIZED: case ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED: case ALUA_ACCESS_STATE_STANDBY: case ALUA_ACCESS_STATE_UNAVAILABLE: @@ -649,7 +649,7 @@ core_alua_check_transition(int state, int *primary) static char *core_alua_dump_state(int state) { switch (state) { - case ALUA_ACCESS_STATE_ACTIVE_OPTMIZED: + case ALUA_ACCESS_STATE_ACTIVE_OPTIMIZED: return "Active/Optimized"; case ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED: return "Active/NonOptimized"; @@ -1349,7 +1349,7 @@ struct t10_alua_tg_pt_gp *core_alua_allocate_tg_pt_gp(struct se_device *dev, tg_pt_gp->tg_pt_gp_dev = dev; tg_pt_gp->tg_pt_gp_md_buf_len = ALUA_MD_BUF_LEN; atomic_set(&tg_pt_gp->tg_pt_gp_alua_access_state, - ALUA_ACCESS_STATE_ACTIVE_OPTMIZED); + ALUA_ACCESS_STATE_ACTIVE_OPTIMIZED); /* * Enable both explicit and implicit ALUA support by default */ diff --git a/drivers/target/target_core_alua.h b/drivers/target/target_core_alua.h index e826a65..88e2e83 100644 --- a/drivers/target/target_core_alua.h +++ b/drivers/target/target_core_alua.h @@ -15,7 +15,7 @@ * * from spc4r17 section 6.27 Table 245 */ -#define ALUA_ACCESS_STATE_ACTIVE_OPTMIZED 0x0 +#define ALUA_ACCESS_STATE_ACTIVE_OPTIMIZED 0x0 #define ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED 0x1 #define ALUA_ACCESS_STATE_STANDBY 0x2 #define ALUA_ACCESS_STATE_UNAVAILABLE 0x3 -- 1.7.12.4 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 06/11] target_core_alua: Validate ALUA state transition
As we now can modify the list of supported states we need to validate the requested ALUA state when doing a state transition. Signed-off-by: Hannes Reinecke --- drivers/target/target_core_alua.c | 85 ++- 1 file changed, 56 insertions(+), 29 deletions(-) diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index a16115e..a420778 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -41,7 +41,8 @@ #include "target_core_alua.h" #include "target_core_ua.h" -static sense_reason_t core_alua_check_transition(int state, int *primary); +static sense_reason_t core_alua_check_transition(int state, int valid, +int *primary); static int core_alua_set_tg_pt_secondary_state( struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, struct se_port *port, int explicit, int offline); @@ -210,7 +211,7 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd) unsigned char *ptr; sense_reason_t rc = TCM_NO_SENSE; u32 len = 4; /* Skip over RESERVED area in header */ - int alua_access_state, primary = 0; + int alua_access_state, primary = 0, valid_states; u16 tg_pt_id, rtpi; if (!l_port) @@ -252,6 +253,7 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd) rc = TCM_UNSUPPORTED_SCSI_OPCODE; goto out; } + valid_states = l_tg_pt_gp->tg_pt_gp_alua_supported_states; ptr = &buf[4]; /* Skip over RESERVED area in header */ @@ -263,7 +265,8 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd) * the state is a primary or secondary target port asymmetric * access state. */ - rc = core_alua_check_transition(alua_access_state, &primary); + rc = core_alua_check_transition(alua_access_state, + valid_states, &primary); if (rc) { /* * If the SET TARGET PORT GROUPS attempts to establish @@ -614,21 +617,57 @@ out: return 0; } +static char *core_alua_dump_state(int state) +{ + switch (state) { + case ALUA_ACCESS_STATE_ACTIVE_OPTIMIZED: + return "Active/Optimized"; + case ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED: + return "Active/NonOptimized"; + case ALUA_ACCESS_STATE_STANDBY: + return "Standby"; + case ALUA_ACCESS_STATE_UNAVAILABLE: + return "Unavailable"; + case ALUA_ACCESS_STATE_OFFLINE: + return "Offline"; + case ALUA_ACCESS_STATE_TRANSITION: + return "Transitioning"; + default: + return "Unknown"; + } + + return NULL; +} + /* * Check implicit and explicit ALUA state change request. */ static sense_reason_t -core_alua_check_transition(int state, int *primary) +core_alua_check_transition(int state, int valid, int *primary) { + /* +* OPTIMIZED, NON-OPTIMIZED, STANDBY and UNAVAILABLE are +* defined as primary target port asymmetric access states. +*/ switch (state) { case ALUA_ACCESS_STATE_ACTIVE_OPTIMIZED: + if (!(valid & ALUA_AO_SUP)) + goto not_supported; + *primary = 1; + break; case ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED: + if (!(valid & ALUA_AN_SUP)) + goto not_supported; + *primary = 1; + break; case ALUA_ACCESS_STATE_STANDBY: + if (!(valid & ALUA_S_SUP)) + goto not_supported; + *primary = 1; + break; case ALUA_ACCESS_STATE_UNAVAILABLE: - /* -* OPTIMIZED, NON-OPTIMIZED, STANDBY and UNAVAILABLE are -* defined as primary target port asymmetric access states. -*/ + if (!(valid & ALUA_U_SUP)) + goto not_supported; *primary = 1; break; case ALUA_ACCESS_STATE_OFFLINE: @@ -636,6 +675,8 @@ core_alua_check_transition(int state, int *primary) * OFFLINE state is defined as a secondary target port * asymmetric access state. */ + if (!(valid & ALUA_O_SUP)) + goto not_supported; *primary = 0; break; default: @@ -644,26 +685,11 @@ core_alua_check_transition(int state, int *primary) } return 0; -} -static char *core_alua_dump_state(int state) -{ - switch (state) { - case ALUA_ACCESS_STATE_ACTIVE_OPTIMIZED: - return "Active/Optimized"; - case ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED: - return "Active/NonOptimized"
[PATCH 08/11] target_core_alua: store old and pending ALUA state
During state transition we should be storing both the original and the pending state. Signed-off-by: Hannes Reinecke --- drivers/target/target_core_alua.c | 15 ++- include/target/target_core_base.h | 6 -- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index b1d08bf..33e3f23 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -804,12 +804,15 @@ static int core_alua_do_transition_tg_pt( struct se_lun_acl *lacl; struct se_port *port; struct t10_alua_tg_pt_gp_member *mem; - int old_state = 0; + /* * Save the old primary ALUA access state, and set the current state * to ALUA_ACCESS_STATE_TRANSITION. */ - old_state = atomic_read(&tg_pt_gp->tg_pt_gp_alua_access_state); + tg_pt_gp->tg_pt_gp_alua_previous_state = + atomic_read(&tg_pt_gp->tg_pt_gp_alua_access_state); + tg_pt_gp->tg_pt_gp_alua_pending_state = new_state; + atomic_set(&tg_pt_gp->tg_pt_gp_alua_access_state, ALUA_ACCESS_STATE_TRANSITION); tg_pt_gp->tg_pt_gp_alua_access_status = (explicit) ? @@ -890,13 +893,15 @@ static int core_alua_do_transition_tg_pt( /* * Set the current primary ALUA access state to the requested new state */ - atomic_set(&tg_pt_gp->tg_pt_gp_alua_access_state, new_state); + atomic_set(&tg_pt_gp->tg_pt_gp_alua_access_state, + tg_pt_gp->tg_pt_gp_alua_pending_state); pr_debug("Successful %s ALUA transition TG PT Group: %s ID: %hu" " from primary access state %s to %s\n", (explicit) ? "explicit" : "implicit", config_item_name(&tg_pt_gp->tg_pt_gp_group.cg_item), - tg_pt_gp->tg_pt_gp_id, core_alua_dump_state(old_state), - core_alua_dump_state(new_state)); + tg_pt_gp->tg_pt_gp_id, + core_alua_dump_state(tg_pt_gp->tg_pt_gp_alua_previous_state), + core_alua_dump_state(tg_pt_gp->tg_pt_gp_alua_pending_state)); return 0; } diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 933c59d..67b6ca2 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -282,8 +282,10 @@ struct t10_alua_lu_gp_member { struct t10_alua_tg_pt_gp { u16 tg_pt_gp_id; int tg_pt_gp_valid_id; - int tg_pt_gp_alua_supported_states; - int tg_pt_gp_alua_access_status; + u8 tg_pt_gp_alua_pending_state; + u8 tg_pt_gp_alua_previous_state; + u8 tg_pt_gp_alua_supported_states; + u8 tg_pt_gp_alua_access_status; int tg_pt_gp_alua_access_type; int tg_pt_gp_nonop_delay_msecs; int tg_pt_gp_trans_delay_msecs; -- 1.7.12.4 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 00/11] target_core_mod: ALUA updates
Hi Nic, here are some updates to TCM ALUA handling. Apart from some minor fixes and spellchecks the main features are: - Make supported states configurable: We should make the list of supported ALUA states configurable, as some setups would possibly like to support a small subset of ALUA states only. - Asynchronous transitioning: I've switched 'transitioning' handling to use a workqueue, that should allow us to simulate asynchronous transitioning modes. IE TCM should now be capable of handling requests while in transitioning, and properly terminate these with the correct sense code. - Include target device descriptor in VPD page 83 For the ALUA device handler we'd need to identify the target device where a given target port belongs to. So include the respective values in the VPD page. Hannes Reinecke (11): target core: rename (ex,im)plict -> (ex,im)plicit target_core_alua: Store supported ALUA states target_core_alua: Make supported states configurable target_core_alua: Rename ALUA_ACCESS_STATE_OPTIMIZED target_core_alua: spellcheck target_core_alua: Validate ALUA state transition target_core_alua: Allocate ALUA metadata on demand target_core_alua: store old and pending ALUA state target_core_alua: Use workqueue for ALUA transitioning target_core: simplify scsi_name_len calculation target_core_spc: Include target device descriptor in VPD page 83 drivers/target/target_core_alua.c | 456 - drivers/target/target_core_alua.h | 36 ++- drivers/target/target_core_configfs.c | 76 +- drivers/target/target_core_device.c| 6 +- drivers/target/target_core_file.c | 2 +- drivers/target/target_core_pr.c| 24 +- drivers/target/target_core_spc.c | 62 - drivers/target/target_core_transport.c | 4 +- drivers/target/target_core_ua.h| 2 +- include/target/target_core_base.h | 14 +- 10 files changed, 442 insertions(+), 240 deletions(-) -- 1.7.12.4 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 03/11] target_core_alua: Make supported states configurable
Signed-off-by: Hannes Reinecke --- drivers/target/target_core_configfs.c | 50 +++ 1 file changed, 50 insertions(+) diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index d4c28a3..53e9e00 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -2131,6 +2131,55 @@ static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_access_type( SE_DEV_ALUA_TG_PT_ATTR(alua_access_type, S_IRUGO | S_IWUSR); /* + * alua_supported_states + */ +static ssize_t target_core_alua_tg_pt_gp_show_attr_alua_supported_states( + struct t10_alua_tg_pt_gp *tg_pt_gp, + char *page) +{ + return sprintf(page, "%02x\n", + tg_pt_gp->tg_pt_gp_alua_supported_states); +} + +static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_supported_states( + struct t10_alua_tg_pt_gp *tg_pt_gp, + const char *page, + size_t count) +{ + unsigned long tmp; + int new_states, valid_states, ret; + + if (!tg_pt_gp->tg_pt_gp_valid_id) { + pr_err("Unable to do set supported ALUA states on non" + " valid tg_pt_gp ID: %hu\n", + tg_pt_gp->tg_pt_gp_valid_id); + return -EINVAL; + } + + ret = strict_strtoul(page, 0, &tmp); + if (ret < 0) { + pr_err("Unable to extract new supported ALUA states" + " from %s\n", page); + return -EINVAL; + } + new_states = (int)tmp; + valid_states = ALUA_T_SUP | ALUA_O_SUP | ALUA_LBD_SUP | \ + ALUA_U_SUP | ALUA_S_SUP | ALUA_AN_SUP | ALUA_AO_SUP; + + + if (new_states & ~valid_states) { + pr_err("Illegal supported ALUA states: 0x%02x\n", + new_states); + return -EINVAL; + } + + tg_pt_gp->tg_pt_gp_alua_supported_states = new_states; + return count; +} + +SE_DEV_ALUA_TG_PT_ATTR(alua_supported_states, S_IRUGO | S_IWUSR); + +/* * alua_write_metadata */ static ssize_t target_core_alua_tg_pt_gp_show_attr_alua_write_metadata( @@ -2350,6 +2399,7 @@ static struct configfs_attribute *target_core_alua_tg_pt_gp_attrs[] = { &target_core_alua_tg_pt_gp_alua_access_state.attr, &target_core_alua_tg_pt_gp_alua_access_status.attr, &target_core_alua_tg_pt_gp_alua_access_type.attr, + &target_core_alua_tg_pt_gp_alua_supported_states.attr, &target_core_alua_tg_pt_gp_alua_write_metadata.attr, &target_core_alua_tg_pt_gp_nonop_delay_msecs.attr, &target_core_alua_tg_pt_gp_trans_delay_msecs.attr, -- 1.7.12.4 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 09/11] target_core_alua: Use workqueue for ALUA transitioning
Use a workqueue for processing ALUA state transitions; this allows us to process implicit delay properly. Signed-off-by: Hannes Reinecke --- drivers/target/target_core_alua.c | 174 +++--- include/target/target_core_base.h | 4 + 2 files changed, 128 insertions(+), 50 deletions(-) diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index 33e3f23..166bee6 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -761,8 +761,7 @@ static int core_alua_write_tpg_metadata( * Called with tg_pt_gp->tg_pt_gp_md_mutex held */ static int core_alua_update_tpg_primary_metadata( - struct t10_alua_tg_pt_gp *tg_pt_gp, - int primary_state) + struct t10_alua_tg_pt_gp *tg_pt_gp) { unsigned char *md_buf; struct t10_wwn *wwn = &tg_pt_gp->tg_pt_gp_dev->t10_wwn; @@ -781,7 +780,8 @@ static int core_alua_update_tpg_primary_metadata( "tg_pt_gp_id=%hu\n" "alua_access_state=0x%02x\n" "alua_access_status=0x%02x\n", - tg_pt_gp->tg_pt_gp_id, primary_state, + tg_pt_gp->tg_pt_gp_id, + tg_pt_gp->tg_pt_gp_alua_pending_state, tg_pt_gp->tg_pt_gp_alua_access_status); snprintf(path, ALUA_METADATA_PATH_LEN, @@ -793,36 +793,17 @@ static int core_alua_update_tpg_primary_metadata( return rc; } -static int core_alua_do_transition_tg_pt( - struct t10_alua_tg_pt_gp *tg_pt_gp, - struct se_port *l_port, - struct se_node_acl *nacl, - int new_state, - int explicit) +static void core_alua_do_transition_tg_pt_work(struct work_struct *work) { + struct t10_alua_tg_pt_gp *tg_pt_gp = container_of(work, + struct t10_alua_tg_pt_gp, tg_pt_gp_transition_work.work); + struct se_device *dev = tg_pt_gp->tg_pt_gp_dev; struct se_dev_entry *se_deve; struct se_lun_acl *lacl; struct se_port *port; struct t10_alua_tg_pt_gp_member *mem; - - /* -* Save the old primary ALUA access state, and set the current state -* to ALUA_ACCESS_STATE_TRANSITION. -*/ - tg_pt_gp->tg_pt_gp_alua_previous_state = - atomic_read(&tg_pt_gp->tg_pt_gp_alua_access_state); - tg_pt_gp->tg_pt_gp_alua_pending_state = new_state; - - atomic_set(&tg_pt_gp->tg_pt_gp_alua_access_state, - ALUA_ACCESS_STATE_TRANSITION); - tg_pt_gp->tg_pt_gp_alua_access_status = (explicit) ? - ALUA_STATUS_ALTERED_BY_EXPLICIT_STPG : - ALUA_STATUS_ALTERED_BY_IMPLICIT_ALUA; - /* -* Check for the optional ALUA primary state transition delay -*/ - if (tg_pt_gp->tg_pt_gp_trans_delay_msecs != 0) - msleep_interruptible(tg_pt_gp->tg_pt_gp_trans_delay_msecs); + bool explicit = (tg_pt_gp->tg_pt_gp_alua_access_status == +ALUA_STATUS_ALTERED_BY_EXPLICIT_STPG); spin_lock(&tg_pt_gp->tg_pt_gp_lock); list_for_each_entry(mem, &tg_pt_gp->tg_pt_gp_mem_list, @@ -857,9 +838,12 @@ static int core_alua_do_transition_tg_pt( if (!lacl) continue; - if (explicit && - (nacl != NULL) && (nacl == lacl->se_lun_nacl) && - (l_port != NULL) && (l_port == port)) + if ((tg_pt_gp->tg_pt_gp_alua_access_status == +ALUA_STATUS_ALTERED_BY_EXPLICIT_STPG) && + (tg_pt_gp->tg_pt_gp_alua_nacl != NULL) && + (tg_pt_gp->tg_pt_gp_alua_nacl == lacl->se_lun_nacl) && + (tg_pt_gp->tg_pt_gp_alua_port != NULL) && + (tg_pt_gp->tg_pt_gp_alua_port == port)) continue; core_scsi3_ua_allocate(lacl->se_lun_nacl, @@ -887,7 +871,7 @@ static int core_alua_do_transition_tg_pt( */ if (tg_pt_gp->tg_pt_gp_write_metadata) { mutex_lock(&tg_pt_gp->tg_pt_gp_md_mutex); - core_alua_update_tpg_primary_metadata(tg_pt_gp, new_state); + core_alua_update_tpg_primary_metadata(tg_pt_gp); mutex_unlock(&tg_pt_gp->tg_pt_gp_md_mutex); } /* @@ -902,6 +886,87 @@ static int core_alua_do_transition_tg_pt( tg_pt_gp->tg_pt_gp_id, core_alua_dump_state(tg_pt_gp->tg_pt_gp_alua_previous_state), core_alua_dump_state(tg_pt_gp->tg_pt_gp_alua_pending_state)); + spin_lock(&dev->t10_alua.tg_pt_gps_lock); + atomic_dec(&tg_pt_gp->tg_pt_gp_ref_cnt); + smp_mb__after_atomic_dec(); + spin_unlock(&dev->t10_alua.tg_pt_gps_lock); + + if (tg_pt_gp->tg_pt_gp_transition_complete) + com
[PATCH 07/11] target_core_alua: Allocate ALUA metadata on demand
We should only allocate ALUA metadata if we're actually going to write them. Signed-off-by: Hannes Reinecke --- drivers/target/target_core_alua.c | 70 +-- drivers/target/target_core_alua.h | 3 ++ include/target/target_core_base.h | 3 -- 3 files changed, 34 insertions(+), 42 deletions(-) diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index a420778..b1d08bf 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -762,16 +762,22 @@ static int core_alua_write_tpg_metadata( */ static int core_alua_update_tpg_primary_metadata( struct t10_alua_tg_pt_gp *tg_pt_gp, - int primary_state, - unsigned char *md_buf) + int primary_state) { + unsigned char *md_buf; struct t10_wwn *wwn = &tg_pt_gp->tg_pt_gp_dev->t10_wwn; char path[ALUA_METADATA_PATH_LEN]; - int len; + int len, rc; + + md_buf = kzalloc(ALUA_MD_BUF_LEN, GFP_KERNEL); + if (!md_buf) { + pr_err("Unable to allocate buf for ALUA metadata\n"); + return -ENOMEM; + } memset(path, 0, ALUA_METADATA_PATH_LEN); - len = snprintf(md_buf, tg_pt_gp->tg_pt_gp_md_buf_len, + len = snprintf(md_buf, ALUA_MD_BUF_LEN, "tg_pt_gp_id=%hu\n" "alua_access_state=0x%02x\n" "alua_access_status=0x%02x\n", @@ -782,14 +788,15 @@ static int core_alua_update_tpg_primary_metadata( "/var/target/alua/tpgs_%s/%s", &wwn->unit_serial[0], config_item_name(&tg_pt_gp->tg_pt_gp_group.cg_item)); - return core_alua_write_tpg_metadata(path, md_buf, len); + rc = core_alua_write_tpg_metadata(path, md_buf, len); + kfree(md_buf); + return rc; } static int core_alua_do_transition_tg_pt( struct t10_alua_tg_pt_gp *tg_pt_gp, struct se_port *l_port, struct se_node_acl *nacl, - unsigned char *md_buf, int new_state, int explicit) { @@ -877,8 +884,7 @@ static int core_alua_do_transition_tg_pt( */ if (tg_pt_gp->tg_pt_gp_write_metadata) { mutex_lock(&tg_pt_gp->tg_pt_gp_md_mutex); - core_alua_update_tpg_primary_metadata(tg_pt_gp, - new_state, md_buf); + core_alua_update_tpg_primary_metadata(tg_pt_gp, new_state); mutex_unlock(&tg_pt_gp->tg_pt_gp_md_mutex); } /* @@ -909,19 +915,12 @@ int core_alua_do_port_transition( struct t10_alua_lu_gp *lu_gp; struct t10_alua_lu_gp_member *lu_gp_mem, *local_lu_gp_mem; struct t10_alua_tg_pt_gp *tg_pt_gp; - unsigned char *md_buf; int primary, valid_states; valid_states = l_tg_pt_gp->tg_pt_gp_alua_supported_states; if (core_alua_check_transition(new_state, valid_states, &primary) != 0) return -EINVAL; - md_buf = kzalloc(l_tg_pt_gp->tg_pt_gp_md_buf_len, GFP_KERNEL); - if (!md_buf) { - pr_err("Unable to allocate buf for ALUA metadata\n"); - return -ENOMEM; - } - local_lu_gp_mem = l_dev->dev_alua_lu_gp_mem; spin_lock(&local_lu_gp_mem->lu_gp_mem_lock); lu_gp = local_lu_gp_mem->lu_gp; @@ -939,10 +938,9 @@ int core_alua_do_port_transition( * success. */ core_alua_do_transition_tg_pt(l_tg_pt_gp, l_port, l_nacl, - md_buf, new_state, explicit); + new_state, explicit); atomic_dec(&lu_gp->lu_gp_ref_cnt); smp_mb__after_atomic_dec(); - kfree(md_buf); return 0; } /* @@ -992,7 +990,7 @@ int core_alua_do_port_transition( * success. */ core_alua_do_transition_tg_pt(tg_pt_gp, port, - nacl, md_buf, new_state, explicit); + nacl, new_state, explicit); spin_lock(&dev->t10_alua.tg_pt_gps_lock); atomic_dec(&tg_pt_gp->tg_pt_gp_ref_cnt); @@ -1014,7 +1012,6 @@ int core_alua_do_port_transition( atomic_dec(&lu_gp->lu_gp_ref_cnt); smp_mb__after_atomic_dec(); - kfree(md_buf); return 0; } @@ -1023,13 +1020,18 @@ int core_alua_do_port_transition( */ static int core_alua_update_tpg_secondary_metadata( struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, - struct se_port *port, - unsigned char *md_buf, - u32 md_buf_len) + struct se_port *port) { + unsigned char *md_buf; struct se_portal_group *se_tpg = port->sep_tpg; char path[ALUA_METADATA_PATH_LEN], wwn[ALUA_SECONDARY_METADATA_WWN_LEN]; - int len; + int len, rc; + + md_buf = kzallo
[PATCH 02/11] target_core_alua: Store supported ALUA states
The supported ALUA states might be different for individual devices, so store it in a separate field. Signed-off-by: Hannes Reinecke --- drivers/target/target_core_alua.c | 14 -- drivers/target/target_core_alua.h | 11 +++ include/target/target_core_base.h | 1 + 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index 8297d37..255e83c 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -117,12 +117,7 @@ target_emulate_report_target_port_groups(struct se_cmd *cmd) /* * Set supported ASYMMETRIC ACCESS State bits */ - buf[off] = 0x80; /* T_SUP */ - buf[off] |= 0x40; /* O_SUP */ - buf[off] |= 0x8; /* U_SUP */ - buf[off] |= 0x4; /* S_SUP */ - buf[off] |= 0x2; /* AN_SUP */ - buf[off++] |= 0x1; /* AO_SUP */ + buf[off++] |= tg_pt_gp->tg_pt_gp_alua_supported_states; /* * TARGET PORT GROUP */ @@ -1367,6 +1362,13 @@ struct t10_alua_tg_pt_gp *core_alua_allocate_tg_pt_gp(struct se_device *dev, tg_pt_gp->tg_pt_gp_trans_delay_msecs = ALUA_DEFAULT_TRANS_DELAY_MSECS; tg_pt_gp->tg_pt_gp_implicit_trans_secs = ALUA_DEFAULT_IMPLICIT_TRANS_SECS; + /* +* Enable all supported states +*/ + tg_pt_gp->tg_pt_gp_alua_supported_states = + ALUA_T_SUP | ALUA_O_SUP | \ + ALUA_U_SUP | ALUA_S_SUP | ALUA_AN_SUP | ALUA_AO_SUP; + if (def_group) { spin_lock(&dev->t10_alua.tg_pt_gps_lock); tg_pt_gp->tg_pt_gp_id = diff --git a/drivers/target/target_core_alua.h b/drivers/target/target_core_alua.h index 74cf0c0..e826a65 100644 --- a/drivers/target/target_core_alua.h +++ b/drivers/target/target_core_alua.h @@ -23,6 +23,17 @@ #define ALUA_ACCESS_STATE_TRANSITION 0xf /* + * from spc4r36j section 6.37 Table 306 + */ +#define ALUA_T_SUP 0x80 +#define ALUA_O_SUP 0x40 +#define ALUA_LBD_SUP 0x10 +#define ALUA_U_SUP 0x08 +#define ALUA_S_SUP 0x04 +#define ALUA_AN_SUP0x02 +#define ALUA_AO_SUP0x01 + +/* * REPORT_TARGET_PORT_GROUP STATUS CODE * * from spc4r17 section 6.27 Table 246 diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 1c6e54d..21f4bd5 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -282,6 +282,7 @@ struct t10_alua_lu_gp_member { struct t10_alua_tg_pt_gp { u16 tg_pt_gp_id; int tg_pt_gp_valid_id; + int tg_pt_gp_alua_supported_states; int tg_pt_gp_alua_access_status; int tg_pt_gp_alua_access_type; int tg_pt_gp_nonop_delay_msecs; -- 1.7.12.4 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 05/11] target_core_alua: spellcheck
Signed-off-by: Hannes Reinecke --- drivers/target/target_core_alua.c | 18 +- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index 593de80..a16115e 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -325,7 +325,7 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd) spin_unlock(&dev->t10_alua.tg_pt_gps_lock); } else { /* -* Extact the RELATIVE TARGET PORT IDENTIFIER to identify +* Extract the RELATIVE TARGET PORT IDENTIFIER to identify * the Target Port in question for the the incoming * SET_TARGET_PORT_GROUPS op. */ @@ -482,7 +482,7 @@ static inline int core_alua_state_transition( u8 *alua_ascq) { /* -* Allowed CDBs for ALUA_ACCESS_STATE_TRANSITIO as defined by +* Allowed CDBs for ALUA_ACCESS_STATE_TRANSITION as defined by * spc4r17 section 5.9.2.5 */ switch (cdb[0]) { @@ -510,9 +510,9 @@ static inline int core_alua_state_transition( } /* - * return 1: Is used to signal LUN not accecsable, and check condition/not ready + * return 1: Is used to signal LUN not accessible, and check condition/not ready * return 0: Used to signal success - * reutrn -1: Used to signal failure, and invalid cdb field + * return -1: Used to signal failure, and invalid cdb field */ sense_reason_t target_alua_state_check(struct se_cmd *cmd) @@ -797,7 +797,7 @@ static int core_alua_do_transition_tg_pt( * change, a device server shall establish a unit attention * condition for the initiator port associated with every I_T * nexus with the additional sense code set to ASYMMETRIC -* ACCESS STATE CHAGED. +* ACCESS STATE CHANGED. * * After an explicit target port asymmetric access state * change, a device server shall establish a unit attention @@ -941,7 +941,7 @@ int core_alua_do_port_transition( continue; /* * If the target behavior port asymmetric access state -* is changed for any target port group accessiable via +* is changed for any target port group accessible via * a logical unit within a LU group, the target port * behavior group asymmetric access states for the same * target port group accessible via other logical units @@ -1227,7 +1227,7 @@ void core_alua_free_lu_gp(struct t10_alua_lu_gp *lu_gp) * struct se_device is released via core_alua_free_lu_gp_mem(). * * If the passed lu_gp does NOT match the default_lu_gp, assume -* we want to re-assocate a given lu_gp_mem with default_lu_gp. +* we want to re-associate a given lu_gp_mem with default_lu_gp. */ spin_lock(&lu_gp_mem->lu_gp_mem_lock); if (lu_gp != default_lu_gp) @@ -1467,7 +1467,7 @@ void core_alua_free_tg_pt_gp( * been called from target_core_alua_drop_tg_pt_gp(). * * Here we remove *tg_pt_gp from the global list so that -* no assications *OR* explicit ALUA via SET_TARGET_PORT_GROUPS +* no associations *OR* explicit ALUA via SET_TARGET_PORT_GROUPS * can be made while we are releasing struct t10_alua_tg_pt_gp. */ spin_lock(&dev->t10_alua.tg_pt_gps_lock); @@ -1503,7 +1503,7 @@ void core_alua_free_tg_pt_gp( * core_alua_free_tg_pt_gp_mem(). * * If the passed tg_pt_gp does NOT match the default_tg_pt_gp, -* assume we want to re-assocate a given tg_pt_gp_mem with +* assume we want to re-associate a given tg_pt_gp_mem with * default_tg_pt_gp. */ spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); -- 1.7.12.4 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 01/11] target core: rename (ex,im)plict -> (ex,im)plicit
Signed-off-by: Hannes Reinecke --- drivers/target/target_core_alua.c | 110 - drivers/target/target_core_alua.h | 20 +++--- drivers/target/target_core_configfs.c | 26 drivers/target/target_core_device.c| 6 +- drivers/target/target_core_file.c | 2 +- drivers/target/target_core_pr.c| 24 +++ drivers/target/target_core_spc.c | 6 +- drivers/target/target_core_transport.c | 4 +- drivers/target/target_core_ua.h| 2 +- include/target/target_core_base.h | 2 +- 10 files changed, 101 insertions(+), 101 deletions(-) diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index 4724410..8297d37 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -44,7 +44,7 @@ static sense_reason_t core_alua_check_transition(int state, int *primary); static int core_alua_set_tg_pt_secondary_state( struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, - struct se_port *port, int explict, int offline); + struct se_port *port, int explicit, int offline); static u16 alua_lu_gps_counter; static u32 alua_lu_gps_count; @@ -175,7 +175,7 @@ target_emulate_report_target_port_groups(struct se_cmd *cmd) if (ext_hdr != 0) { buf[4] = 0x10; /* -* Set the implict transition time (in seconds) for the application +* Set the implicit transition time (in seconds) for the application * client to use as a base for it's transition timeout value. * * Use the current tg_pt_gp_mem -> tg_pt_gp membership from the LUN @@ -188,7 +188,7 @@ target_emulate_report_target_port_groups(struct se_cmd *cmd) spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); tg_pt_gp = tg_pt_gp_mem->tg_pt_gp; if (tg_pt_gp) - buf[5] = tg_pt_gp->tg_pt_gp_implict_trans_secs; + buf[5] = tg_pt_gp->tg_pt_gp_implicit_trans_secs; spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); } } @@ -199,7 +199,7 @@ target_emulate_report_target_port_groups(struct se_cmd *cmd) } /* - * SET_TARGET_PORT_GROUPS for explict ALUA operation. + * SET_TARGET_PORT_GROUPS for explicit ALUA operation. * * See spc4r17 section 6.35 */ @@ -232,7 +232,7 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd) return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; /* -* Determine if explict ALUA via SET_TARGET_PORT_GROUPS is allowed +* Determine if explicit ALUA via SET_TARGET_PORT_GROUPS is allowed * for the local tg_pt_gp. */ l_tg_pt_gp_mem = l_port->sep_alua_tg_pt_gp_mem; @@ -251,9 +251,9 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd) } spin_unlock(&l_tg_pt_gp_mem->tg_pt_gp_mem_lock); - if (!(l_tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_EXPLICT_ALUA)) { + if (!(l_tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_EXPLICIT_ALUA)) { pr_debug("Unable to process SET_TARGET_PORT_GROUPS" - " while TPGS_EXPLICT_ALUA is disabled\n"); + " while TPGS_EXPLICIT_ALUA is disabled\n"); rc = TCM_UNSUPPORTED_SCSI_OPCODE; goto out; } @@ -620,7 +620,7 @@ out: } /* - * Check implict and explict ALUA state change request. + * Check implicit and explicit ALUA state change request. */ static sense_reason_t core_alua_check_transition(int state, int *primary) @@ -676,10 +676,10 @@ char *core_alua_dump_status(int status) switch (status) { case ALUA_STATUS_NONE: return "None"; - case ALUA_STATUS_ALTERED_BY_EXPLICT_STPG: - return "Altered by Explict STPG"; - case ALUA_STATUS_ALTERED_BY_IMPLICT_ALUA: - return "Altered by Implict ALUA"; + case ALUA_STATUS_ALTERED_BY_EXPLICIT_STPG: + return "Altered by Explicit STPG"; + case ALUA_STATUS_ALTERED_BY_IMPLICIT_ALUA: + return "Altered by Implicit ALUA"; default: return "Unknown"; } @@ -770,7 +770,7 @@ static int core_alua_do_transition_tg_pt( struct se_node_acl *nacl, unsigned char *md_buf, int new_state, - int explict) + int explicit) { struct se_dev_entry *se_deve; struct se_lun_acl *lacl; @@ -784,9 +784,9 @@ static int core_alua_do_transition_tg_pt( old_state = atomic_read(&tg_pt_gp->tg_pt_gp_alua_access_state); atomic_set(&tg_pt_gp->tg_pt_gp_alua_access_state, ALUA_ACCESS_STATE_TRANSITION); - tg_pt_gp->tg_pt_gp_alua_access_status = (explict) ? - ALUA_STATUS_ALTERED_BY_EXPLICT_STPG : -
[PATCH 2/5] tcm_loop: Implement transport offline
Add attribute 'transport_status' to simulate link failure. Signed-off-by: Hannes Reinecke --- drivers/target/loopback/tcm_loop.c | 53 +- drivers/target/loopback/tcm_loop.h | 4 +++ 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index 57d5a95..f81ebe4 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -178,7 +178,10 @@ static void tcm_loop_submission_work(struct work_struct *work) set_host_byte(sc, DID_NO_CONNECT); goto out_done; } - + if (tl_tpg->tl_transport_status == TCM_TRANSPORT_OFFLINE) { + set_host_byte(sc, DID_TRANSPORT_DISRUPTED); + goto out_done; + } tl_nexus = tl_hba->tl_nexus; if (!tl_nexus) { scmd_printk(KERN_ERR, sc, "TCM_Loop I_T Nexus" @@ -1064,8 +1067,56 @@ check_newline: TF_TPG_BASE_ATTR(tcm_loop, nexus, S_IRUGO | S_IWUSR); +static ssize_t tcm_loop_tpg_show_transport_status( + struct se_portal_group *se_tpg, + char *page) +{ + struct tcm_loop_tpg *tl_tpg = container_of(se_tpg, + struct tcm_loop_tpg, tl_se_tpg); + const char *status = NULL; + ssize_t ret = -EINVAL; + + switch (tl_tpg->tl_transport_status) { + case TCM_TRANSPORT_ONLINE: + status = "online"; + break; + case TCM_TRANSPORT_OFFLINE: + status = "offline"; + break; + default: + break; + } + + if (status) + ret = snprintf(page, PAGE_SIZE, "%s\n", status); + + return ret; +} + +static ssize_t tcm_loop_tpg_store_transport_status( + struct se_portal_group *se_tpg, + const char *page, + size_t count) +{ + struct tcm_loop_tpg *tl_tpg = container_of(se_tpg, + struct tcm_loop_tpg, tl_se_tpg); + + if (!strncmp(page, "online", 6)) { + tl_tpg->tl_transport_status = TCM_TRANSPORT_ONLINE; + return count; + } + if (!strncmp(page, "offline", 7)) { + tl_tpg->tl_transport_status = TCM_TRANSPORT_OFFLINE; + return count; + } + return -EINVAL; +} + +TF_TPG_BASE_ATTR(tcm_loop, transport_status, S_IRUGO | S_IWUSR); + static struct configfs_attribute *tcm_loop_tpg_attrs[] = { &tcm_loop_tpg_nexus.attr, + &tcm_loop_tpg_transport_status.attr, NULL, }; diff --git a/drivers/target/loopback/tcm_loop.h b/drivers/target/loopback/tcm_loop.h index dd7a84e..56528f7 100644 --- a/drivers/target/loopback/tcm_loop.h +++ b/drivers/target/loopback/tcm_loop.h @@ -40,8 +40,12 @@ struct tcm_loop_nacl { struct se_node_acl se_node_acl; }; +#define TCM_TRANSPORT_ONLINE 0 +#define TCM_TRANSPORT_OFFLINE 1 + struct tcm_loop_tpg { unsigned short tl_tpgt; + unsigned short tl_transport_status; atomic_t tl_tpg_port_count; struct se_portal_group tl_se_tpg; struct tcm_loop_hba *tl_hba; -- 1.7.12.4 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 5/5] tcm_loop: Implement target reset
Implement target reset by resetting the transport status. Signed-off-by: Hannes Reinecke --- drivers/target/loopback/tcm_loop.c | 27 +++ 1 file changed, 27 insertions(+) diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index febe166..d52c0aa 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -392,6 +392,32 @@ static int tcm_loop_device_reset(struct scsi_cmnd *sc) return (ret == TMR_FUNCTION_COMPLETE) ? SUCCESS : FAILED; } +static int tcm_loop_target_reset(struct scsi_cmnd *sc) +{ + struct tcm_loop_hba *tl_hba; + struct tcm_loop_tpg *tl_tpg; + int ret = FAILED; + + /* +* Locate the tcm_loop_hba_t pointer +*/ + tl_hba = *(struct tcm_loop_hba **)shost_priv(sc->device->host); + if (!tl_hba) { + pr_err("Unable to perform device reset without" + " active I_T Nexus\n"); + return FAILED; + } + /* +* Locate the tl_tpg pointer from TargetID in sc->device->id +*/ + tl_tpg = &tl_hba->tl_hba_tpgs[sc->device->id]; + if (tl_tpg) { + tl_tpg->tl_transport_status = TCM_TRANSPORT_ONLINE; + return SUCCESS; + } + return FAILED; +} + static int tcm_loop_slave_alloc(struct scsi_device *sd) { set_bit(QUEUE_FLAG_BIDI, &sd->request_queue->queue_flags); @@ -421,6 +447,7 @@ static struct scsi_host_template tcm_loop_driver_template = { .change_queue_type = tcm_loop_change_queue_type, .eh_abort_handler = tcm_loop_abort_task, .eh_device_reset_handler = tcm_loop_device_reset, + .eh_target_reset_handler = tcm_loop_target_reset, .can_queue = 1024, .this_id= -1, .sg_tablesize = 256, -- 1.7.12.4 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 1/5] tcm_loop: Check for valid hba in tcm_loop_drop_nexus()
Signed-off-by: Hannes Reinecke --- drivers/target/loopback/tcm_loop.c | 5 - 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index 0f6d69d..57d5a95 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -932,7 +932,10 @@ static int tcm_loop_drop_nexus( struct tcm_loop_nexus *tl_nexus; struct tcm_loop_hba *tl_hba = tpg->tl_hba; - tl_nexus = tpg->tl_hba->tl_nexus; + if (!tl_hba) + return -ENODEV; + + tl_nexus = tl_hba->tl_nexus; if (!tl_nexus) return -ENODEV; -- 1.7.12.4 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 0/5] Updates for tcm_loop
Hi Nic, here are some updates to tcm_loop I've done during ALUA testing. I've implemented a 'transport_state' attribute to simulate transport failure and added command abort callbacks. Hannes Reinecke (5): tcm_loop: Check for valid hba in tcm_loop_drop_nexus() tcm_loop: Implement transport offline tcm_loop: separate out tcm_loop_issue_tmr tcm_loop: TCQ and command abort support tcm_loop: Implement target reset drivers/target/loopback/tcm_loop.c | 233 +++-- drivers/target/loopback/tcm_loop.h | 6 + include/target/target_core_base.h | 1 + 3 files changed, 204 insertions(+), 36 deletions(-) -- 1.7.12.4 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 4/5] tcm_loop: TCQ and command abort support
Implement TCQ support, which enables us to do proper command abort, too. Signed-off-by: Hannes Reinecke --- drivers/target/loopback/tcm_loop.c | 71 +++--- drivers/target/loopback/tcm_loop.h | 2 ++ 2 files changed, 69 insertions(+), 4 deletions(-) diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index 7232976..febe166 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -135,6 +135,21 @@ static int tcm_loop_change_queue_depth( return sdev->queue_depth; } +static int tcm_loop_change_queue_type(struct scsi_device *sdev, int tag) +{ + if (sdev->tagged_supported) { + scsi_set_tag_type(sdev, tag); + + if (tag) + scsi_activate_tcq(sdev, sdev->queue_depth); + else + scsi_deactivate_tcq(sdev, sdev->queue_depth); + } else + tag = 0; + + return tag; +} + /* * Locate the SAM Task Attr from struct scsi_cmnd * */ @@ -236,6 +251,7 @@ static int tcm_loop_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *sc) } tl_cmd->sc = sc; + tl_cmd->sc_cmd_tag = sc->tag; INIT_WORK(&tl_cmd->work, tcm_loop_submission_work); queue_work(tcm_loop_workqueue, &tl_cmd->work); return 0; @@ -247,7 +263,7 @@ static int tcm_loop_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *sc) */ static int tcm_loop_issue_tmr(struct tcm_loop_tpg *tl_tpg, struct tcm_loop_nexus *tl_nexus, - int lun, enum tcm_tmreq_table tmr) + int lun, int task, enum tcm_tmreq_table tmr) { struct se_cmd *se_cmd = NULL; struct se_session *se_sess; @@ -283,6 +299,9 @@ static int tcm_loop_issue_tmr(struct tcm_loop_tpg *tl_tpg, if (rc < 0) goto release; + if (tmr == TMR_ABORT_TASK) + se_cmd->se_tmr_req->ref_task_tag = task; + /* * Locate the underlying TCM struct se_lun */ @@ -310,6 +329,36 @@ release: return ret; } +static int tcm_loop_abort_task(struct scsi_cmnd *sc) +{ + struct tcm_loop_hba *tl_hba; + struct tcm_loop_nexus *tl_nexus; + struct tcm_loop_tpg *tl_tpg; + int ret = FAILED; + + /* +* Locate the tcm_loop_hba_t pointer +*/ + tl_hba = *(struct tcm_loop_hba **)shost_priv(sc->device->host); + /* +* Locate the tl_nexus and se_sess pointers +*/ + tl_nexus = tl_hba->tl_nexus; + if (!tl_nexus) { + pr_err("Unable to perform device reset without" + " active I_T Nexus\n"); + return FAILED; + } + + /* +* Locate the tl_tpg pointer from TargetID in sc->device->id +*/ + tl_tpg = &tl_hba->tl_hba_tpgs[sc->device->id]; + ret = tcm_loop_issue_tmr(tl_tpg, tl_nexus, sc->device->lun, +sc->tag, TMR_ABORT_TASK); + return (ret == TMR_FUNCTION_COMPLETE) ? SUCCESS : FAILED; +} + /* * Called from SCSI EH process context to issue a LUN_RESET TMR * to struct scsi_device @@ -338,8 +387,8 @@ static int tcm_loop_device_reset(struct scsi_cmnd *sc) * Locate the tl_tpg pointer from TargetID in sc->device->id */ tl_tpg = &tl_hba->tl_hba_tpgs[sc->device->id]; - ret = tcm_loop_issue_tmr(tl_tpg, tl_nexus, -sc->device->lun, TMR_LUN_RESET); + ret = tcm_loop_issue_tmr(tl_tpg, tl_nexus, sc->device->lun, +0, TMR_LUN_RESET); return (ret == TMR_FUNCTION_COMPLETE) ? SUCCESS : FAILED; } @@ -351,6 +400,15 @@ static int tcm_loop_slave_alloc(struct scsi_device *sd) static int tcm_loop_slave_configure(struct scsi_device *sd) { + if (sd->tagged_supported) { + scsi_activate_tcq(sd, sd->queue_depth); + scsi_adjust_queue_depth(sd, MSG_SIMPLE_TAG, + sd->host->cmd_per_lun); + } else { + scsi_adjust_queue_depth(sd, 0, + sd->host->cmd_per_lun); + } + return 0; } @@ -360,6 +418,8 @@ static struct scsi_host_template tcm_loop_driver_template = { .name = "TCM_Loopback", .queuecommand = tcm_loop_queuecommand, .change_queue_depth = tcm_loop_change_queue_depth, + .change_queue_type = tcm_loop_change_queue_type, + .eh_abort_handler = tcm_loop_abort_task, .eh_device_reset_handler = tcm_loop_device_reset, .can_queue = 1024, .this_id= -1, @@ -719,7 +779,10 @@ static void tcm_loop_set_default_node_attributes(struct se_node_acl *se_acl) static u32 tcm_loop_get_task_tag(struct se_cmd *se_cmd) { - return 1; + struct tcm_loop_cmd *tl_cmd
[PATCH 3/5] tcm_loop: separate out tcm_loop_issue_tmr
No functional change. Signed-off-by: Hannes Reinecke --- drivers/target/loopback/tcm_loop.c | 83 +++--- include/target/target_core_base.h | 1 + 2 files changed, 51 insertions(+), 33 deletions(-) diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index f81ebe4..7232976 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -245,41 +245,21 @@ static int tcm_loop_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *sc) * Called from SCSI EH process context to issue a LUN_RESET TMR * to struct scsi_device */ -static int tcm_loop_device_reset(struct scsi_cmnd *sc) +static int tcm_loop_issue_tmr(struct tcm_loop_tpg *tl_tpg, + struct tcm_loop_nexus *tl_nexus, + int lun, enum tcm_tmreq_table tmr) { struct se_cmd *se_cmd = NULL; - struct se_portal_group *se_tpg; struct se_session *se_sess; + struct se_portal_group *se_tpg; struct tcm_loop_cmd *tl_cmd = NULL; - struct tcm_loop_hba *tl_hba; - struct tcm_loop_nexus *tl_nexus; struct tcm_loop_tmr *tl_tmr = NULL; - struct tcm_loop_tpg *tl_tpg; - int ret = FAILED, rc; - /* -* Locate the tcm_loop_hba_t pointer -*/ - tl_hba = *(struct tcm_loop_hba **)shost_priv(sc->device->host); - /* -* Locate the tl_nexus and se_sess pointers -*/ - tl_nexus = tl_hba->tl_nexus; - if (!tl_nexus) { - pr_err("Unable to perform device reset without" - " active I_T Nexus\n"); - return FAILED; - } - se_sess = tl_nexus->se_sess; - /* -* Locate the tl_tpg and se_tpg pointers from TargetID in sc->device->id -*/ - tl_tpg = &tl_hba->tl_hba_tpgs[sc->device->id]; - se_tpg = &tl_tpg->tl_se_tpg; + int ret = TMR_FUNCTION_FAILED, rc; tl_cmd = kmem_cache_zalloc(tcm_loop_cmd_cache, GFP_KERNEL); if (!tl_cmd) { pr_err("Unable to allocate memory for tl_cmd\n"); - return FAILED; + return ret; } tl_tmr = kzalloc(sizeof(struct tcm_loop_tmr), GFP_KERNEL); @@ -290,6 +270,8 @@ static int tcm_loop_device_reset(struct scsi_cmnd *sc) init_waitqueue_head(&tl_tmr->tl_tmr_wait); se_cmd = &tl_cmd->tl_se_cmd; + se_tpg = &tl_tpg->tl_se_tpg; + se_sess = tl_nexus->se_sess; /* * Initialize struct se_cmd descriptor from target_core_mod infrastructure */ @@ -297,17 +279,20 @@ static int tcm_loop_device_reset(struct scsi_cmnd *sc) DMA_NONE, MSG_SIMPLE_TAG, &tl_cmd->tl_sense_buf[0]); - rc = core_tmr_alloc_req(se_cmd, tl_tmr, TMR_LUN_RESET, GFP_KERNEL); + rc = core_tmr_alloc_req(se_cmd, tl_tmr, tmr, GFP_KERNEL); if (rc < 0) goto release; + /* -* Locate the underlying TCM struct se_lun from sc->device->lun +* Locate the underlying TCM struct se_lun */ - if (transport_lookup_tmr_lun(se_cmd, sc->device->lun) < 0) + if (transport_lookup_tmr_lun(se_cmd, lun) < 0) { + ret = TMR_LUN_DOES_NOT_EXIST; goto release; + } /* -* Queue the TMR to TCM Core and sleep waiting for tcm_loop_queue_tm_rsp() -* to wake us up. +* Queue the TMR to TCM Core and sleep waiting for +* tcm_loop_queue_tm_rsp() to wake us up. */ transport_generic_handle_tmr(se_cmd); wait_event(tl_tmr->tl_tmr_wait, atomic_read(&tl_tmr->tmr_complete)); @@ -315,8 +300,7 @@ static int tcm_loop_device_reset(struct scsi_cmnd *sc) * The TMR LUN_RESET has completed, check the response status and * then release allocations. */ - ret = (se_cmd->se_tmr_req->response == TMR_FUNCTION_COMPLETE) ? - SUCCESS : FAILED; + ret = se_cmd->se_tmr_req->response; release: if (se_cmd) transport_generic_free_cmd(se_cmd, 1); @@ -326,6 +310,39 @@ release: return ret; } +/* + * Called from SCSI EH process context to issue a LUN_RESET TMR + * to struct scsi_device + */ +static int tcm_loop_device_reset(struct scsi_cmnd *sc) +{ + struct tcm_loop_hba *tl_hba; + struct tcm_loop_nexus *tl_nexus; + struct tcm_loop_tpg *tl_tpg; + int ret = FAILED; + + /* +* Locate the tcm_loop_hba_t pointer +*/ + tl_hba = *(struct tcm_loop_hba **)shost_priv(sc->device->host); + /* +* Locate the tl_nexus and se_sess pointers +*/ + tl_nexus = tl_hba->tl_nexus; + if (!tl_nexus) { + pr_err("Unable to perform device reset without" + " active I_T Nexus\n"); + return FAILED; + } + /* +* Locate the tl_tpg