Re: [PATCH-v4 0/5] Fix LUN_RESET active I/O + TMR handling
Hi Himanshu & Co, On Fri, 2016-02-12 at 00:48 -0800, Nicholas A. Bellinger wrote: > On Fri, 2016-02-12 at 05:30 +, Himanshu Madhani wrote: > Thanks for the crash dump output. > > So it's a t_state = TRANSPORT_WRITE_PENDING descriptor with > SAM_STAT_CHECK_CONDITION + cmd_kref.refcount = 0: > > struct qla_tgt_cmd { > se_cmd = { > scsi_status = 0x2 > se_cmd_flags = 0x80090d, > > > > cmd_kref = { > refcount = { > counter = 0x0 > } > }, > } > > The se_cmd_flags=0x80090d translation to enum se_cmd_flags_table: > > - SCF_TRANSPORT_TASK_SENSE > - SCF_EMULATED_TASK_SENSE > - SCF_SCSI_DATA_CDB > - SCF_SE_LUN_CMD > - SCF_SENT_CHECK_CONDITION > - SCF_USE_CPUID > After groking your dump some more: For SAM_STAT_CHECK_CONDITION with t_state = TRANSPORT_WRITE_PENDING plus se_cmd->transport_state = 0x880 bits set, is: - CMD_T_DEV_ACTIVE - CMD_T_FABRIC_STOP and sense buffer = 0x70 00 0b 00 00 00 00 0a 00 00 00 00 29 03 00, which is the following from sense_info_table[]: [TCM_CHECK_CONDITION_ABORT_CMD] = { .key = ABORTED_COMMAND, .asc = 0x29, /* BUS DEVICE RESET FUNCTION OCCURRED */ .ascq = 0x03, }, The descriptor looks like it did make it to tcm_qla2xxx_complete_free() -> transport_generic_free_cmd() with both qla_tgt_cmd->cmd_sent_to_fw=0, and qla_tgt_cmd->write_data_transferred=0 set. The best I can tell, it looks like tcm_qla2xxx_handle_data_work() -> transport_generic_request_failure() w/ TCM_CHECK_CONDITION_ABORT_CMD is occurring.. So to confirm, this specific bug was not a result of active I/O LUN_RESET w/ CMD_T_ABORTED during session disconnect, or otherwise. > > > I can recreate this issue at will within 5 minute of triggering sg_reset > > with following steps > > > > 1. Export 4 RAM disk LUNs on each of 2 port adapter. Initiator will see 8 > > RAM disk targets > > 2. Start IO with 4K block size and 8 threads with 80% write 20% read and > > 100% dandom. > > (I am using vdbench for generating IO. I can provide setup/config script > > if needed) > > 3. Start sg_reset for each LUNs with first device, bus and host with 120s > > delay. (I¹ve attached > > My script that I am using for triggering sg_reset) > > > > Thanks, will keep looking and try to reproduce with your script. So here's my test setup with 3x Intel P3600 NVMe/IBLOCK backends, across dual ISP2532 ports: o- / . [...] o- backstores .. [...] | o- fileio ... [0 Storage Object] | o- iblock .. [3 Storage Objects] | | o- nvme0n1 [/dev/nvme0n1, in use] | | o- nvme1n1 [/dev/nvme1n1, in use] | | o- nvme2n1 [/dev/nvme2n1, in use] | o- pscsi [0 Storage Object] | o- rd_mcp ... [1 Storage Object] | o- ramdisk .. [16.0G, ramdisk, not in use] o- qla2xxx ... [2 Targets] | o- 21:00:00:24:ff:48:97:7e ... [enabled] | | o- acls .. [1 ACL] | | | o- 21:00:00:24:ff:48:97:7c . [3 Mapped LUNs] | | | o- mapped_lun0 ... [lun0 (rw)] | | | o- mapped_lun1 ... [lun1 (rw)] | | | o- mapped_lun2 ... [lun2 (rw)] | | o- luns . [3 LUNs] | | o- lun0 [iblock/nvme0n1 (/dev/nvme0n1)] | | o- lun1 [iblock/nvme1n1 (/dev/nvme1n1)] | | o- lun2 [iblock/nvme2n1 (/dev/nvme2n1)] | o- 21:00:00:24:ff:48:97:7f ... [enabled] | o- acls .. [1 ACL] | | o- 21:00:00:24:ff:48:97:7d . [3 Mapped LUNs] | | o- mapped_lun0 ... [lun0 (rw)] | |
aicasm: fix kbuild for separated build directories
I've recently been experimenting with building in emulated architecture containers which allow me to build natively on my laptop a kernel for any architecture which qemu will emulate. To do this, I've been building into build/$(uname -m) and this caused the aicasm stuff to fail to build (using CONFIG_AIC7XXX_BUILD_FIRMWARE=y). I think this patch corrects the problem, but I'm not hugely familiar with the kbuild infrastructure so I cc'd an expert for a second opinion. James --- diff --git a/drivers/scsi/aic7xxx/Makefile b/drivers/scsi/aic7xxx/Makefile index 741d818..c21c922 100644 --- a/drivers/scsi/aic7xxx/Makefile +++ b/drivers/scsi/aic7xxx/Makefile @@ -5,7 +5,7 @@ # # Let kbuild descend into aicasm when cleaning -subdir-+= aicasm +subdir-+= aicasm/ obj-$(CONFIG_SCSI_AIC7XXX) += aic7xxx.o obj-$(CONFIG_SCSI_AIC79XX) += aic79xx.o @@ -55,9 +55,9 @@ aicasm-7xxx-opts-$(CONFIG_AIC7XXX_REG_PRETTY_PRINT) := \ ifeq ($(CONFIG_AIC7XXX_BUILD_FIRMWARE),y) $(obj)/aic7xxx_seq.h: $(src)/aic7xxx.seq $(src)/aic7xxx.reg $(obj)/aicasm/aicasm - $(obj)/aicasm/aicasm -I$(src) -r $(obj)/aic7xxx_reg.h \ + $(obj)/aicasm/aicasm -I$(srctree)/$(src) -r $(obj)/aic7xxx_reg.h \ $(aicasm-7xxx-opts-y) -o $(obj)/aic7xxx_seq.h \ - $(src)/aic7xxx.seq + $(srctree)/$(src)/aic7xxx.seq $(aic7xxx-gen-y): $(obj)/aic7xxx_seq.h else @@ -72,14 +72,14 @@ aicasm-79xx-opts-$(CONFIG_AIC79XX_REG_PRETTY_PRINT) := \ ifeq ($(CONFIG_AIC79XX_BUILD_FIRMWARE),y) $(obj)/aic79xx_seq.h: $(src)/aic79xx.seq $(src)/aic79xx.reg $(obj)/aicasm/aicasm - $(obj)/aicasm/aicasm -I$(src) -r $(obj)/aic79xx_reg.h \ - $(aicasm-79xx-opts-y) -o $(obj)/aic79xx_seq.h \ - $(src)/aic79xx.seq + $(obj)/aicasm/aicasm -I$(srctree)/$(src) -r $(obj)/aic79xx_reg.h \ + $(aicasm-79xx-opts-y) -o $@ \ + $(srctree)/$(src)/aic79xx.seq $(aic79xx-gen-y): $(obj)/aic79xx_seq.h else $(obj)/aic79xx_reg_print.c: $(src)/aic79xx_reg_print.c_shipped endif -$(obj)/aicasm/aicasm: $(src)/aicasm/*.[chyl] - $(MAKE) -C $(src)/aicasm +$(obj)/aicasm/aicasm: + $(Q)$(MAKE) $(build)=drivers/scsi/aic7xxx/aicasm all diff --git a/drivers/scsi/aic7xxx/aicasm/Makefile b/drivers/scsi/aic7xxx/aicasm/Makefile index b98c5c1..73559f0 100644 --- a/drivers/scsi/aic7xxx/aicasm/Makefile +++ b/drivers/scsi/aic7xxx/aicasm/Makefile @@ -1,19 +1,22 @@ -PROG= aicasm +PROG= $(obj)/aicasm + +all: $(PROG) .SUFFIXES= .l .y .c .h -CSRCS= aicasm.c aicasm_symbol.c -YSRCS= aicasm_gram.y aicasm_macro_gram.y -LSRCS= aicasm_scan.l aicasm_macro_scan.l +CSRCS= $(srctree)/$(src)/aicasm.c $(srctree)/$(src)/aicasm_symbol.c +YSRCS= $(src)/aicasm_gram.y $(src)/aicasm_macro_gram.y +LSRCS= $(src)/aicasm_scan.l $(src)/aicasm_macro_scan.l -GENHDRS= aicdb.h $(YSRCS:.y=.h) -GENSRCS= $(YSRCS:.y=.c) $(LSRCS:.l=.c) +GENHDRS= $(obj)/aicdb.h $(patsubst $(src)/%.y,$(obj)/%.h,$(YSRCS)) +GENSRCS= $(patsubst $(src)/%.y,$(obj)/%.c,$(YSRCS)) \ + $(patsubst $(src)/%.l,$(obj)/%.c,$(LSRCS)) -SRCS= ${CSRCS} ${GENSRCS} +SRCS= $(CSRCS) $(GENSRCS) LIBS= -ldb clean-files:= ${GENSRCS} ${GENHDRS} $(YSRCS:.y=.output) $(PROG) # Override default kernel CFLAGS. This is a userland app. -AICASM_CFLAGS:= -I/usr/include -I. +AICASM_CFLAGS:= -I/usr/include -I. -I$(srctree)/$(src) LEX= flex YACC= bison YFLAGS= -d @@ -32,22 +35,23 @@ YFLAGS+= -t -v LFLAGS= -d endif -$(PROG): ${GENHDRS} $(SRCS) - $(AICASM_CC) $(AICASM_CFLAGS) $(SRCS) -o $(PROG) $(LIBS) +$(PROG): $(GENHDRS) $(SRCS) + echo "SRCS=$(SRCS)" + $(AICASM_CC) $(AICASM_CFLAGS) $(SRCS) -o $@ $(LIBS) -aicdb.h: +$(obj)/aicdb.h: @if [ -e "/usr/include/db4/db_185.h" ]; then\ - echo "#include " > aicdb.h; \ + echo "#include " > $(obj)/aicdb.h;\ elif [ -e "/usr/include/db3/db_185.h" ]; then \ - echo "#include " > aicdb.h; \ + echo "#include " > $(obj)/aicdb.h;\ elif [ -e "/usr/include/db2/db_185.h" ]; then \ - echo "#include " > aicdb.h; \ + echo "#include " > $(obj)/aicdb.h;\ elif [ -e "/usr/include/db1/db_185.h" ]; then \ - echo "#include " > aicdb.h; \ + echo "#include " > $(obj)/aicdb.h;\ elif [ -e "/usr/include/db/db_185.h" ]; then \ - echo "#include " > aicdb.h;\ + echo "#include " > $(obj)/aicdb.h; \ elif [ -e "/usr/include/db_185.h" ]; then \ - echo "#include " > aicdb.h; \ + echo "#include " > $(obj)/aicdb.h;\ else
Re: [PATCH] Use ida_simple for SCSI iSCSI transport session id
On 02/12/2016 11:54 AM, James Bottomley wrote: > On Fri, 2016-02-12 at 09:38 -0800, Lee Duncan wrote: >> The scsi_transport_iscsi module already uses the ida_simple >> routines for managing the target ID, if requested to do >> so. This change replaces an ever-increasing atomic integer >> that tracks the session ID itself with the ida_simple >> family of routines. This means that the session ID >> will be reclaimed and can be reused when the session >> is freed. > > Is reusing session ID's really a good idea? I think it is if we do it by the iscsi rfc. We have two issues. 1. For iSCSI's iSID we need a 24 bit id. The iSID + initiator name is the SCSI initiator port ID, so targets want the iSID to be reused for things like persistent reservation tracking. There are a couple red hat bugzillas. I am not sure if they are open though. Here is a KB https://access.redhat.com/solutions/66861 for more info. We have been lazy and did not implement this and were just reusing part of the session->sid. 2. For the kobject/sysfs name we want a unique name/id. Linux boxes stay up a long time and some users login and logout of sessions a lot. We roll over and have collisions. Lee's patch was only meant to fix this. The reuse part was not meant to fix #1, and so it does not handle every case like you suspect. To fix everything how about this: - Use Lee's patch to fix #2. We do not need the iSID to match the sysfs name. Userspace does not do any type of iSCSI iSID <-> kernel session id matching. - For #1, in the userespace node db code we can implement some iSID allocation/management code that follows the spec. We can also add a blacklist there in case we find broken targets. -- 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 v2 3/7] ibmvscsi: Replace magic values in set_adpater_info() with defines
Reviewed-by: Manoj Kumar --- Manoj Kumar On 2/10/2016 7:32 PM, Tyrel Datwyler wrote: Add defines for mad version and mad os_type, and replace the magic numbers in set_adapter_info() accordingly. Signed-off-by: Tyrel Datwyler --- drivers/scsi/ibmvscsi/ibmvscsi.c | 8 drivers/scsi/ibmvscsi/viosrp.h | 3 +++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index c888ea1..4b09a9b 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -283,8 +283,8 @@ static void set_adapter_info(struct ibmvscsi_host_data *hostdata) hostdata->madapter_info.partition_number = cpu_to_be32(partition_number); - hostdata->madapter_info.mad_version = cpu_to_be32(1); - hostdata->madapter_info.os_type = cpu_to_be32(2); + hostdata->madapter_info.mad_version = cpu_to_be32(SRP_MAD_VERSION_1); + hostdata->madapter_info.os_type = cpu_to_be32(SRP_MAD_OS_LINUX); } /** @@ -1398,7 +1398,7 @@ static void adapter_info_rsp(struct srp_event_struct *evt_struct) hostdata->host->max_sectors = be32_to_cpu(hostdata->madapter_info.port_max_txu[0]) >> 9; - if (be32_to_cpu(hostdata->madapter_info.os_type) == 3 && + if (be32_to_cpu(hostdata->madapter_info.os_type) == SRP_MAD_OS_AIX && strcmp(hostdata->madapter_info.srp_version, "1.6a") <= 0) { dev_err(hostdata->dev, "host (Ver. %s) doesn't support large transfers\n", hostdata->madapter_info.srp_version); @@ -1407,7 +1407,7 @@ static void adapter_info_rsp(struct srp_event_struct *evt_struct) hostdata->host->sg_tablesize = MAX_INDIRECT_BUFS; } - if (be32_to_cpu(hostdata->madapter_info.os_type) == 3) { + if (be32_to_cpu(hostdata->madapter_info.os_type) == SRP_MAD_OS_AIX) { enable_fast_fail(hostdata); return; } diff --git a/drivers/scsi/ibmvscsi/viosrp.h b/drivers/scsi/ibmvscsi/viosrp.h index 3d20851..d0f689b 100644 --- a/drivers/scsi/ibmvscsi/viosrp.h +++ b/drivers/scsi/ibmvscsi/viosrp.h @@ -221,7 +221,10 @@ struct mad_adapter_info_data { char srp_version[8]; char partition_name[96]; __be32 partition_number; +#define SRP_MAD_VERSION_1 1 __be32 mad_version; +#define SRP_MAD_OS_LINUX 2 +#define SRP_MAD_OS_AIX 3 __be32 os_type; __be32 port_max_txu[8]; /* per-port maximum transfer */ }; -- 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 v7 3/3] add support for DWC UFS Host Controller
On Fri, Feb 12, 2016 at 11:52 AM, Joao Pinto wrote: > Hi Rob, > > On 2/12/2016 4:36 PM, Rob Herring wrote: >> On Thu, Feb 11, 2016 at 12:13:06PM +, Joao Pinto wrote: >>> +Required properties: >>> +- compatible: compatible string ("snps,ufshcd-1.0", >>> "snps,ufshcd-1.1" >>> + or "snps,ufshcd-2.0") >> >> History has taught us this needs to have a vendor specific compatible >> string as well. Don't necessarily have to define it now, but just state >> a vendor string is needed too. > > The compatibility string already as the "snps" which is the acronym for > Synopsys > which is the HW Controller vendor. Isn't this enough? Go look drivers for any licensed IP: DW PCIe, DW GMAC, USB EHCI controllers (pretty much all licensed IP), etc. They all have variations either from versions of the IP, configuration of the IP, "enhancements" by the licensee, integration quirks, or all of the above. Rob -- 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: [PATCHv6 00/23] ALUA device handler update, part II
On 02/12/2016 12:25 AM, Hannes Reinecke wrote: > as promised here is now the second part of my ALUA device handler update. Hello Hannes, Thanks for the quick respin. The first lockdep warning I noticed with the previous version is gone. But I saw the following with this patch series: [ cut here ] WARNING: CPU: 7 PID: 43 at kernel/locking/mutex.c:869 mutex_trylock+0x1ad/0x1c0() DEBUG_LOCKS_WARN_ON(in_interrupt()) CPU: 7 PID: 43 Comm: ksoftirqd/7 Tainted: GE 4.5.0-rc3+ #8 Call Trace: [] dump_stack+0x6b/0xa4 [] warn_slowpath_common+0x8b/0xd0 [] warn_slowpath_fmt+0x41/0x70 [] mutex_trylock+0x1ad/0x1c0 [] alua_check+0x31/0x260 [scsi_dh_alua] [] alua_check_sense+0x6e/0x90 [scsi_dh_alua] [] scsi_check_sense+0x71/0x270 [] scsi_decide_disposition+0x18e/0x200 [] scsi_softirq_done+0x65/0x150 [] __blk_mq_complete_request+0x81/0x100 [] blk_mq_complete_request+0x17/0x20 [] scsi_mq_done+0x16/0x20 [] srp_process_rsp+0x13e/0x280 [ib_srp] [] srp_recv_done+0x187/0x380 [ib_srp] [] __ib_process_cq+0x43/0xc0 [ib_core] [] ib_poll_handler+0x2d/0x80 [ib_core] [] irq_poll_softirq+0xa8/0xf0 [] __do_softirq+0xf6/0x240 [] run_ksoftirqd+0x1a/0x60 [] smpboot_thread_fn+0x113/0x1d0 [] kthread+0xe4/0x100 [] ret_from_fork+0x3f/0x70 ---[ end trace 34fb3b7c104f6c3d ]--- Can you also address this warning ? Thanks, Bart. -- 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] Use ida_simple for SCSI iSCSI transport session id
On Fri, 2016-02-12 at 09:38 -0800, Lee Duncan wrote: > The scsi_transport_iscsi module already uses the ida_simple > routines for managing the target ID, if requested to do > so. This change replaces an ever-increasing atomic integer > that tracks the session ID itself with the ida_simple > family of routines. This means that the session ID > will be reclaimed and can be reused when the session > is freed. Is reusing session ID's really a good idea? For sequential sessions it means that the ID of the next session will be re-used, i.e. the same as the previous sessions, which could lead to target confusion. I think local uniqueness of session IDs is more important than wrap around because sessions are short lived entities and the chances of the same session being alive by the time we've wrapped is pretty tiny. If you can demostrate a multi-target problem, perhaps we should rather fix this by making the next session id a target local quantity? 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 v7 3/3] add support for DWC UFS Host Controller
Hi Rob, On 2/12/2016 4:36 PM, Rob Herring wrote: > On Thu, Feb 11, 2016 at 12:13:06PM +, Joao Pinto wrote: >> +Required properties: >> +- compatible: compatible string ("snps,ufshcd-1.0", >> "snps,ufshcd-1.1" >> + or "snps,ufshcd-2.0") > > History has taught us this needs to have a vendor specific compatible > string as well. Don't necessarily have to define it now, but just state > a vendor string is needed too. The compatibility string already as the "snps" which is the acronym for Synopsys which is the HW Controller vendor. Isn't this enough? > >> +- reg : >> +- interrupts: >> + >> +Example: >> +ufs@0xd000 { >> +compatible = "snps,ufshcd-2.0"; >> +reg = < 0xd000 0x1 >; >> +interrupts = < 24 >; >> +}; Thanks, Joao -- 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] Use ida_simple for SCSI iSCSI transport session id
The scsi_transport_iscsi module already uses the ida_simple routines for managing the target ID, if requested to do so. This change replaces an ever-increasing atomic integer that tracks the session ID itself with the ida_simple family of routines. This means that the session ID will be reclaimed and can be reused when the session is freed. Note that no maximum is placed on this value, though user-space currently only seems to use the lower 24-bits. It seems better to handle this in user space, though, than to limit the value range for the session ID here. Signed-off-by: Lee Duncan --- drivers/scsi/scsi_transport_iscsi.c | 19 ++- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 441481623fb9..50a10bf214a8 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -79,7 +79,8 @@ struct iscsi_internal { struct transport_container session_cont; }; -static atomic_t iscsi_session_nr; /* sysfs session id for next new session */ +static DEFINE_IDA(iscsi_session_id_ida); + static struct workqueue_struct *iscsi_eh_timer_workq; static DEFINE_IDA(iscsi_sess_ida); @@ -2074,7 +2075,12 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id) int err; ihost = shost->shost_data; - session->sid = atomic_add_return(1, &iscsi_session_nr); + session->sid = ida_simple_get(&iscsi_session_id_ida, 0, 0, GFP_KERNEL); + if (session->sid < 0) { + iscsi_cls_session_printk(KERN_ERR, session, +"Failure in Session ID Allocation\n"); + return session->sid; + } if (target_id == ISCSI_MAX_TARGET) { id = ida_simple_get(&iscsi_sess_ida, 0, 0, GFP_KERNEL); @@ -2082,7 +2088,8 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id) if (id < 0) { iscsi_cls_session_printk(KERN_ERR, session, "Failure in Target ID Allocation\n"); - return id; + err = id; + goto release_session_id_ida; } session->target_id = (unsigned int)id; session->ida_used = true; @@ -2109,6 +2116,8 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id) release_ida: if (session->ida_used) ida_simple_remove(&iscsi_sess_ida, session->target_id); +release_session_id_ida: + ida_simple_remove(&iscsi_session_id_ida, session->target_id); return err; } @@ -2214,6 +2223,7 @@ void iscsi_free_session(struct iscsi_cls_session *session) { ISCSI_DBG_TRANS_SESSION(session, "Freeing session\n"); iscsi_session_event(session, ISCSI_KEVENT_DESTROY_SESSION); + ida_simple_remove(&iscsi_session_id_ida, session->target_id); put_device(&session->dev); } EXPORT_SYMBOL_GPL(iscsi_free_session); @@ -4524,8 +4534,6 @@ static __init int iscsi_transport_init(void) printk(KERN_INFO "Loading iSCSI transport class v%s.\n", ISCSI_TRANSPORT_VERSION); - atomic_set(&iscsi_session_nr, 0); - err = class_register(&iscsi_transport_class); if (err) return err; @@ -4598,6 +4606,7 @@ static void __exit iscsi_transport_exit(void) class_unregister(&iscsi_endpoint_class); class_unregister(&iscsi_iface_class); class_unregister(&iscsi_transport_class); + ida_destroy(&iscsi_session_id_ida); } module_init(iscsi_transport_init); -- 2.1.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: megaraid_sas: Task management support
> "Sumit" == Sumit Saxena writes: Sumit, >> It looks like the code is correct but the patch just deleted a tab Sumit> Yes code is correct, tab got deleted accidentally. Please submit a patch to correct the formatting. -- Martin K. Petersen Oracle Linux Engineering -- 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 v2 3/7] ibmvscsi: Replace magic values in set_adpater_info() with defines
> "James" == James Bottomley writes: James> OK we need a re-review then ... I'll hold off pushing for now. -- Martin K. Petersen Oracle Linux Engineering -- 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 v2 0/7] ibmvscsi code cleanup
> "Tyrel" == Tyrel Datwyler writes: Tyrel> Fixed up a couple spots that were out of line with the PAPR in Tyrel> regards to its defined VSCSI protocol. Did away with some magic Tyrel> numbers directly in the code. Fixed a minor endian issue. Applied to 4.6/scsi-queue. (And added the missing review from Johannes for patch 3 as pointed out by James). -- Martin K. Petersen Oracle Linux Engineering -- 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 v2 3/7] ibmvscsi: Replace magic values in set_adpater_info() with defines
On Fri, 2016-02-12 at 08:51 -0800, Tyrel Datwyler wrote: > On 02/12/2016 08:43 AM, James Bottomley wrote: > > On Wed, 2016-02-10 at 19:32 -0600, Tyrel Datwyler wrote: > > > Add defines for mad version and mad os_type, and replace the > > > magic > > > numbers in set_adapter_info() accordingly. > > > > > > Signed-off-by: Tyrel Datwyler > > > --- > > > > Is there some reason you didn't carry the review tag over from > > this: > > > > http://mid.gmane.org/20160204084459.gw27...@c203.arch.suse.de > > > > ? > > > > James > > The patch is slightly changed from v1. A define for AIX os type was > added as mentioned in the cover letter v2 changes, and I moved the > defines to the mad_adapter_info_data structure around the fields they > apply. OK we need a re-review then ... 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 v2 3/7] ibmvscsi: Replace magic values in set_adpater_info() with defines
On 02/12/2016 08:43 AM, James Bottomley wrote: > On Wed, 2016-02-10 at 19:32 -0600, Tyrel Datwyler wrote: >> Add defines for mad version and mad os_type, and replace the magic >> numbers in set_adapter_info() accordingly. >> >> Signed-off-by: Tyrel Datwyler >> --- > > Is there some reason you didn't carry the review tag over from this: > > http://mid.gmane.org/20160204084459.gw27...@c203.arch.suse.de > > ? > > James The patch is slightly changed from v1. A define for AIX os type was added as mentioned in the cover letter v2 changes, and I moved the defines to the mad_adapter_info_data structure around the fields they apply. -Tyrel > > -- > 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: [PATCH v2 3/7] ibmvscsi: Replace magic values in set_adpater_info() with defines
On Wed, 2016-02-10 at 19:32 -0600, Tyrel Datwyler wrote: > Add defines for mad version and mad os_type, and replace the magic > numbers in set_adapter_info() accordingly. > > Signed-off-by: Tyrel Datwyler > --- Is there some reason you didn't carry the review tag over from this: http://mid.gmane.org/20160204084459.gw27...@c203.arch.suse.de ? 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 v7 3/3] add support for DWC UFS Host Controller
On Thu, Feb 11, 2016 at 12:13:06PM +, Joao Pinto wrote: > This patch has the goal to add support for DesignWare UFS Controller > specific operations and to add specific platform and pci drivers. > > Signed-off-by: Joao Pinto > --- > Changes v6->v7 (Arnd Bergmann): > - Changed DT node name (to ufs only) and the memory address (to 0xd00) > - Removed CONFIG_PM from the PCI glue driver (pm.h already does this) > - No other changes are necessary in ufshcd.c because of the link up notify > function usage (it is simpler now) > - Removed the PHY mentioning since the Test Chip is not a real PHY for real > world usage, since it is a test chip for prototyping with a very specific > usage > - Added again the Test Chip 20-bit option > Changes v5->v6: > - Patch bad format fixed > Changes v4->v5 (Akinobu Mita): > - All functions used only locally in ufshcd-dwc are now declared as static > - ufshcd_dwc_configuration() was removed in ufshcd-dwc and a notify > function (ufshcd_dwc_link_startup_notify) was created to deal with the > DWC specific init routines > - 20-bit RMMI option was removed from Kconfig. Now if MPHY TC is selected > and 40-bit is not then it assumes a 20-bit config > Changes v3->v4 (Arnd Bergmann and Mark Rutland): > - SCSI_UFS_DWC_HOOKS is now silent and selected by the SCSI_UFS_DWC_PLAT > or SCSI_UFS_DWC_PCI > - Compatibility string has the ufs core version for info purposes since > the driver is capable of getting the controller version from its > registers > - Created ufs-dwc-pci glue driver with specific DWC data > - MPHY configuration remains in the ufshcd-dwc since it is unipro > attribute writting only not following the a linux phy framework logic > Changes v2->v3 (Julian Calaby): > - Implement a common DWC code to be used by the platform and pci glue > drivers > - Synopsys ID & Class added to the existing pci driver and specific DWC > was also added to the pci driver > Changes v1->v2 (Akinobu Mita): > - Implement a platform driver that uses the existing UFS core driver > - Add DWC specific code to the existing UFS core driver > > Documentation/devicetree/bindings/ufs/ufs-dwc.txt | 17 + > MAINTAINERS | 6 + > drivers/scsi/ufs/Kconfig | 51 ++ > drivers/scsi/ufs/Makefile | 3 + > drivers/scsi/ufs/ufs-dwc-pci.c| 172 + > drivers/scsi/ufs/ufs-dwc.c| 102 +++ > drivers/scsi/ufs/ufshcd-dwc.c | 739 > ++ > drivers/scsi/ufs/ufshcd-dwc.h | 18 + > drivers/scsi/ufs/ufshci-dwc.h | 42 ++ > drivers/scsi/ufs/unipro.h | 39 ++ > 10 files changed, 1189 insertions(+) > create mode 100644 Documentation/devicetree/bindings/ufs/ufs-dwc.txt > create mode 100644 drivers/scsi/ufs/ufs-dwc-pci.c > create mode 100644 drivers/scsi/ufs/ufs-dwc.c > create mode 100644 drivers/scsi/ufs/ufshcd-dwc.c > create mode 100644 drivers/scsi/ufs/ufshcd-dwc.h > create mode 100644 drivers/scsi/ufs/ufshci-dwc.h > > diff --git a/Documentation/devicetree/bindings/ufs/ufs-dwc.txt > b/Documentation/devicetree/bindings/ufs/ufs-dwc.txt > new file mode 100644 > index 000..3cbfd77 > --- /dev/null > +++ b/Documentation/devicetree/bindings/ufs/ufs-dwc.txt > @@ -0,0 +1,17 @@ > +* Universal Flash Storage (UFS) DesignWare Host Controller > + > +DWC_UFSHC nodes are defined to describe on-chip UFS host controllers. > +Each UFS controller instance should have its own node. > + > +Required properties: > +- compatible: compatible string ("snps,ufshcd-1.0", "snps,ufshcd-1.1" > + or "snps,ufshcd-2.0") History has taught us this needs to have a vendor specific compatible string as well. Don't necessarily have to define it now, but just state a vendor string is needed too. > +- reg : > +- interrupts: > + > +Example: > + ufs@0xd000 { > + compatible = "snps,ufshcd-2.0"; > + reg = < 0xd000 0x1 >; > + interrupts = < 24 >; > + }; -- 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] bio: return EINTR if copying to user space got interrupted
On 16-02-12 03:39 AM, Hannes Reinecke wrote: Commit 35dc248383bbab0a7203fca4d722875bc81ef091 introduced a check for current->mm to see if we have a user space context and only copies data if we do. Now if an IO gets interrupted by a signal data isn't copied into user space any more (as we don't have a user space context) but user space isn't notified about it. This patch modifies the behaviour to return -EINTR from bio_uncopy_user() to notify userland that a signal has interrupted the syscall, otherwise it could lead to a situation where the caller may get a buffer with no data returned. Interesting, the "f091" commit has been in the kernel since 2013 hence your reference to v.3.11 . I always had the feeling that handling signals that interrupted SG_IO calls was skating on thin ice. Hence in ddpt (but not sg_dd nor sgp_dd) the code masks out all signals (that it can) during the SG_IO calls then opens a signal window briefly after a SG_IO ioctl has finished and before the next one starts. This approach used by ddpt is borrowed from dd (in coreutils) which masks signals during its read() and write() calls. Any idea how accurate resid is in this scenario? Doug Gilbert This can be reproduced by issuing SG_IO ioctl()s in one thread while constantly sending signals to it. Fixes: 35dc248 [SCSI] sg: Fix user memory corruption when SG_IO is interrupted by a signal Signed-off-by: Johannes Thumshirn Signed-off-by: Hannes Reinecke Cc: sta...@vger.kernel.org # v.3.11+ --- block/bio.c | 7 +-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/block/bio.c b/block/bio.c index dbabd48..24e5b69 100644 --- a/block/bio.c +++ b/block/bio.c @@ -1090,9 +1090,12 @@ int bio_uncopy_user(struct bio *bio) if (!bio_flagged(bio, BIO_NULL_MAPPED)) { /* * if we're in a workqueue, the request is orphaned, so -* don't copy into a random user address space, just free. +* don't copy into a random user address space, just free +* and return -EINTR so user space doesn't expect any data. */ - if (current->mm && bio_data_dir(bio) == READ) + if (!current->mm) + ret = -EINTR; + else if (bio_data_dir(bio) == READ) ret = bio_copy_to_iter(bio, bmd->iter); if (bmd->is_our_pages) bio_free_pages(bio); -- 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] bio: return EINTR if copying to user space got interrupted
On Fri, 2016-02-12 at 09:39 +0100, Hannes Reinecke wrote: > Commit 35dc248383bbab0a7203fca4d722875bc81ef091 introduced a check for > current->mm to see if we have a user space context and only copies data > if we do. Now if an IO gets interrupted by a signal data isn't copied > into user space any more (as we don't have a user space context) but > user space isn't notified about it. > > This patch modifies the behaviour to return -EINTR from bio_uncopy_user() > to notify userland that a signal has interrupted the syscall, otherwise > it could lead to a situation where the caller may get a buffer with > no data returned. > > This can be reproduced by issuing SG_IO ioctl()s in one thread while > constantly sending signals to it. Well, this is definitely an improvement, since it now indicates to the user that there was a problem instead of silently returning with no data and no error, but it doesn't completely fix the issue. For one thing, if the SG_IO is performed to a sequential media device, the I/O is actually performed, and the position changes, it is just the data that is not copied back. So e.g. a user program making calls to read from a tape device that gets signals and retrying on -EINTR will skip blocks. There is a similar problem already with SG_IO and -ERESTARTSYS. I believe that that only way around this is to mask the signals. (This is also problem with non-idempotent commands, such as COMPARE AND WRITE.) I should mention that the patch "sg: Fix user memory corruption when SG_IO is interrupted by a signal" broke a 3rd-party kernel module that happened to use SG_IO to pass *kernel* addresses for I/O. Which worked for them until the current->mm test was added. (I don't know why they didn't just put I/O on the request queue like everyone else, though.) This patch should go in, though. Reviewed-by: Ewan D. Milne > > Fixes: 35dc248 [SCSI] sg: Fix user memory corruption when SG_IO is > interrupted by a signal > Signed-off-by: Johannes Thumshirn > Signed-off-by: Hannes Reinecke > Cc: sta...@vger.kernel.org # v.3.11+ > --- > block/bio.c | 7 +-- > 1 file changed, 5 insertions(+), 2 deletions(-) > > diff --git a/block/bio.c b/block/bio.c > index dbabd48..24e5b69 100644 > --- a/block/bio.c > +++ b/block/bio.c > @@ -1090,9 +1090,12 @@ int bio_uncopy_user(struct bio *bio) > if (!bio_flagged(bio, BIO_NULL_MAPPED)) { > /* >* if we're in a workqueue, the request is orphaned, so > - * don't copy into a random user address space, just free. > + * don't copy into a random user address space, just free > + * and return -EINTR so user space doesn't expect any data. >*/ > - if (current->mm && bio_data_dir(bio) == READ) > + if (!current->mm) > + ret = -EINTR; > + else if (bio_data_dir(bio) == READ) > ret = bio_copy_to_iter(bio, bmd->iter); > if (bmd->is_our_pages) > bio_free_pages(bio); -- 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] bio: return EINTR if copying to user space got interrupted
On 02/12/2016 05:05 PM, Douglas Gilbert wrote: On 16-02-12 03:39 AM, Hannes Reinecke wrote: Commit 35dc248383bbab0a7203fca4d722875bc81ef091 introduced a check for current->mm to see if we have a user space context and only copies data if we do. Now if an IO gets interrupted by a signal data isn't copied into user space any more (as we don't have a user space context) but user space isn't notified about it. This patch modifies the behaviour to return -EINTR from bio_uncopy_user() to notify userland that a signal has interrupted the syscall, otherwise it could lead to a situation where the caller may get a buffer with no data returned. Interesting, the "f091" commit has been in the kernel since 2013 hence your reference to v.3.11 . I always had the feeling that handling signals that interrupted SG_IO calls was skating on thin ice. Yeah; that bug was really annoying, as occasionally receiving no data whatsoever without any indication makes it really, really hard to debug. Kudos go to Johannes and Ewan for pointing to the offending function. Hence in ddpt (but not sg_dd nor sgp_dd) the code masks out all signals (that it can) during the SG_IO calls then opens a signal window briefly after a SG_IO ioctl has finished and before the next one starts. This approach used by ddpt is borrowed from dd (in coreutils) which masks signals during its read() and write() calls. Any idea how accurate resid is in this scenario? Bah. F*sk knows. That takes far more POSIX knowledge than I have. I would suspect that by masking out signals they'll be marked as pending for the process, and will be delivered once you unmask them. Or dropped, depending. In either case, once they are blocked out the kernel part shouldn't receive a signal, and hence we should be able to receive the data properly. But as noted I'm not a POSIX expert. 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] bio: return EINTR if copying to user space got interrupted
On 02/12/2016 01:39 AM, Hannes Reinecke wrote: Commit 35dc248383bbab0a7203fca4d722875bc81ef091 introduced a check for current->mm to see if we have a user space context and only copies data if we do. Now if an IO gets interrupted by a signal data isn't copied into user space any more (as we don't have a user space context) but user space isn't notified about it. This patch modifies the behaviour to return -EINTR from bio_uncopy_user() to notify userland that a signal has interrupted the syscall, otherwise it could lead to a situation where the caller may get a buffer with no data returned. This can be reproduced by issuing SG_IO ioctl()s in one thread while constantly sending signals to it. Good catch, fix looks good to me. Applied for 4.5. -- Jens Axboe -- 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 v2 1/7] ibmvscsi: Correct values for several viosrp_crq_format enums
Reviewed-by: Manoj Kumar --- Manoj Kumar On 2/10/2016 7:32 PM, Tyrel Datwyler wrote: The enum values for VIOSRP_LINUX_FORMAT and VIOSRP_INLINE_FORMAT are off by one. They are currently defined as 0x06 and 0x07 respetively. These values are defined in PAPR correctly as 0x05 and 0x06. This inconsistency has gone unnoticed as neither enum is currently used. The possible future support of PING messages between the VIOS and client adapter relies on VIOSRP_INLINE_FORMAT crq messages. Corrected these enum values to match PAPR definitions. Signed-off-by: Tyrel Datwyler Reviewed-by: Johannes Thumshirn --- drivers/scsi/ibmvscsi/viosrp.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/ibmvscsi/viosrp.h b/drivers/scsi/ibmvscsi/viosrp.h index 1162430..d1044e9 100644 --- a/drivers/scsi/ibmvscsi/viosrp.h +++ b/drivers/scsi/ibmvscsi/viosrp.h @@ -56,8 +56,8 @@ enum viosrp_crq_formats { VIOSRP_MAD_FORMAT = 0x02, VIOSRP_OS400_FORMAT = 0x03, VIOSRP_AIX_FORMAT = 0x04, - VIOSRP_LINUX_FORMAT = 0x06, - VIOSRP_INLINE_FORMAT = 0x07 + VIOSRP_LINUX_FORMAT = 0x05, + VIOSRP_INLINE_FORMAT = 0x06 }; enum viosrp_crq_status { -- 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 v2 2/7] ibmvscsi: Add and use enums for valid CRQ header values
Tyrel: Thanks for incorporating the suggestions. Reviewed-by: Manoj Kumar --- Manoj Kumar On 2/10/2016 7:32 PM, Tyrel Datwyler wrote: The PAPR defines four valid header values for the first byte of a CRQ message. Namely, an unused/empty message (0x00), a valid command/response entry (0x80), a valid initialization entry (0xC0), and a valid transport event (0xFF). Further, initialization responses have two formats namely initialize (0x01) and initialize complete (0x02). Define these values as enums and use them in the code in place of their magic number equivalents. Signed-off-by: Tyrel Datwyler --- drivers/scsi/ibmvscsi/ibmvscsi.c | 18 +- drivers/scsi/ibmvscsi/viosrp.h | 12 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index adfef9d..c888ea1 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -182,7 +182,7 @@ static struct viosrp_crq *crq_queue_next_crq(struct crq_queue *queue) spin_lock_irqsave(&queue->lock, flags); crq = &queue->msgs[queue->cur]; - if (crq->valid & 0x80) { + if (crq->valid != VIOSRP_CRQ_FREE) { if (++queue->cur == queue->size) queue->cur = 0; @@ -231,7 +231,7 @@ static void ibmvscsi_task(void *data) /* Pull all the valid messages off the CRQ */ while ((crq = crq_queue_next_crq(&hostdata->queue)) != NULL) { ibmvscsi_handle_crq(crq, hostdata); - crq->valid = 0x00; + crq->valid = VIOSRP_CRQ_FREE; } vio_enable_interrupts(vdev); @@ -239,7 +239,7 @@ static void ibmvscsi_task(void *data) if (crq != NULL) { vio_disable_interrupts(vdev); ibmvscsi_handle_crq(crq, hostdata); - crq->valid = 0x00; + crq->valid = VIOSRP_CRQ_FREE; } else { done = 1; } @@ -474,7 +474,7 @@ static int initialize_event_pool(struct event_pool *pool, struct srp_event_struct *evt = &pool->events[i]; memset(&evt->crq, 0x00, sizeof(evt->crq)); atomic_set(&evt->free, 1); - evt->crq.valid = 0x80; + evt->crq.valid = VIOSRP_CRQ_CMD_RSP; evt->crq.IU_length = cpu_to_be16(sizeof(*evt->xfer_iu)); evt->crq.IU_data_ptr = cpu_to_be64(pool->iu_token + sizeof(*evt->xfer_iu) * i); @@ -1767,9 +1767,9 @@ static void ibmvscsi_handle_crq(struct viosrp_crq *crq, struct srp_event_struct *evt_struct = (__force struct srp_event_struct *)crq->IU_data_ptr; switch (crq->valid) { - case 0xC0: /* initialization */ + case VIOSRP_CRQ_INIT_RSP: /* initialization */ switch (crq->format) { - case 0x01: /* Initialization message */ + case VIOSRP_CRQ_INIT: /* Initialization message */ dev_info(hostdata->dev, "partner initialized\n"); /* Send back a response */ rc = ibmvscsi_send_crq(hostdata, 0xC002LL, 0); @@ -1781,7 +1781,7 @@ static void ibmvscsi_handle_crq(struct viosrp_crq *crq, } break; - case 0x02: /* Initialization response */ + case VIOSRP_CRQ_INIT_COMPLETE: /* Initialization response */ dev_info(hostdata->dev, "partner initialization complete\n"); /* Now login */ @@ -1791,7 +1791,7 @@ static void ibmvscsi_handle_crq(struct viosrp_crq *crq, dev_err(hostdata->dev, "unknown crq message type: %d\n", crq->format); } return; - case 0xFF: /* Hypervisor telling us the connection is closed */ + case VIOSRP_CRQ_XPORT_EVENT:/* Hypervisor telling us the connection is closed */ scsi_block_requests(hostdata->host); atomic_set(&hostdata->request_limit, 0); if (crq->format == 0x06) { @@ -1807,7 +1807,7 @@ static void ibmvscsi_handle_crq(struct viosrp_crq *crq, ibmvscsi_reset_host(hostdata); } return; - case 0x80: /* real payload */ + case VIOSRP_CRQ_CMD_RSP:/* real payload */ break; default: dev_err(hostdata->dev, "got an invalid message type 0x%02x\n", diff --git a/drivers/scsi/ibmvscsi/viosrp.h b/drivers/scsi/ibmvscsi/viosrp.h index d1044e9..3d20851 100644 --- a/drivers/scsi/ibmvscsi/viosrp.h +++ b/drivers/scsi/ibmvscsi/viosrp.h @@ -51,6 +51,18 @@ union srp_iu { u8 reserved[SRP_MAX_IU_LEN]; }; +enum v
RE: megaraid_sas: Task management support
> -Original Message- > From: Dan Carpenter [mailto:dan.carpen...@oracle.com] > Sent: Monday, February 08, 2016 11:52 PM > To: sumit.sax...@avagotech.com > Cc: megaraidlinux@avagotech.com; linux-scsi@vger.kernel.org > Subject: re: megaraid_sas: Task management support > > Hello Sumit Saxena, > > The patch 31796fa184ee: "megaraid_sas: Task management support" from Jan > 28, 2016, leads to the following static checker warning: > > drivers/scsi/megaraid/megaraid_sas_base.c:1788 > megasas_update_sdev_properties() > warn: if statement not indented > > drivers/scsi/megaraid/megaraid_sas_base.c > 1781 } else { > 1782 device_id = ((sdev->channel % 2) * > MEGASAS_MAX_DEV_PER_CHANNEL) > 1783 + sdev->id; > 1784 local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)]; > 1785 ld = MR_TargetIdToLdGet(device_id, local_map_ptr); > 1786 raid = MR_LdRaidGet(ld, local_map_ptr); > 1787 > 1788 if (raid->capability.ldPiMode == > MR_PROT_INFO_TYPE_CONTROLLER) > 1789 blk_queue_update_dma_alignment(sdev->request_queue, 0x7); > > It looks like the code is correct but the patch just deleted a tab accidentally. Yes code is correct, tab got deleted accidentally. > > 1790 mr_device_priv_data->is_tm_capable = > 1791 raid->capability.tmCapable; > 1792 } > > regards, > dan carpenter -- 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-v4 0/5] Fix LUN_RESET active I/O + TMR handling
On Fri, 2016-02-12 at 05:30 +, Himanshu Madhani wrote: > Hi Nic, > > > > On 2/11/16, 3:47 PM, "Nicholas A. Bellinger" wrote: > > >On Wed, 2016-02-10 at 22:53 -0800, Nicholas A. Bellinger wrote: > >> On Tue, 2016-02-09 at 18:03 +, Himanshu Madhani wrote: > >> > On 2/8/16, 9:25 PM, "Nicholas A. Bellinger" > >>wrote: > >> > >On Mon, 2016-02-08 at 23:27 +, Himanshu Madhani wrote: > >> > >> > >> > >> I am testing this series with with 4.5.0-rc2+ kernel and I am > >>seeing > >> > >>issue > >> > >> where trying to trigger > >> > >> sg_reset with option of host/device/bus in loop at 120second > >>interval > >> > >> causes call stack. At this point > >> > >> removing configuration hangs indefinitely. See attached dmesg > >>output > >> > >>from > >> > >> my setup. > >> > >> > >> > > > >> > >Thanks alot for testing this. > >> > > > >> > >So It looks like we're still hitting a indefinite schedule() on > >> > >se_cmd->cmd_wait_comp once tcm_qla2xxx session disconnect/reconnect > >> > >occurs, after repeated explicit active I/O remote-port sg_resets. > >> > > > >> > >Does this trigger on the first tcm_qla2xxx session reconnect after > >> > >explicit remote-port sg_reset..? Are session reconnects actively > >>being > >> > >triggered during the test..? > >> > > > >> > >To verify the latter for iscsi-target, I've been using a small patch > >>to > >> > >trigger session reset from TMR kthread context in order to simulate > >>the > >> > >I_T disconnects. Something like that would be useful for verifying > >>with > >> > >tcm_qla2xxx too. > >> > > > >> > >That said, I'll be reproducing with tcm_qla2xxx ports this week, and > >> > >will enable various debug in a WIP branch for testing. > >> > >> Following up here.. > >> > >> So far using my test setup with ISP2532 ports in P2P + RAMDISK_MCP and > >> v4.5-rc1, repeated remote-port active I/O LUN_RESET (sg_reset -d) has > >> been functioning as expected with a blocksize_range=4k-256k + iodepth=32 > >> fio write-verify style workload. > >> > >> No ->cmd_kref -1 OOPsen or qla2xxx initiator generated ABORT_TASKs from > >> outstanding target TAS responses, nor fio write-verify failures to > >> report after 800x remote-port active I/O LUN_RESETS. > >> > >> Next step will be to verify explicit tcm_qla2xxx port + module shutdown > >> after 1K test iterations, and then IBLOCK async completions <-> NVMe > >> backends with the same case. > >> > > > >After letting this test run over-night up to 7k active I/O remote-port > >LUN_RESETs, things are still functioning as expected. > > > >Also, /etc/init.d/target stop was able to successfully shutdown all > >active sessions and unload tcm_qla2xxx after the test run. > > > >So AFAICT, the active I/O remote-port LUN_RESET changes are stable with > >tcm_qla2xxx ports, separate from concurrent session disconnect hung task > >you reported earlier. > > > >That said, I'll likely push this series as-is for -rc4, given that Dan > >has also been able to verify the non conncurrent session disconnect case > >on his setup generating constant ABORT_TASKs, and it's still surviving > >both cases for iscsi-target ports. > > > >Please give the debug patch from last night a shot, and see if we can > >determine the se_cmd states when you hit the hung task. > > I¹ll give your latest debug patch try in a little while > > From the testing that I have done, what is seen is that active IO has > already been completed and qla2xxx driver is waiting for commands to be > Completed and it¹s waiting indefinitely for cmd_wait_comp. > So it looks like there is a missing complete call from target_core. I¹ve > attached our analysis from crash debug on a live system after the issues > happens. > > Thanks for the crash dump output. So it's a t_state = TRANSPORT_WRITE_PENDING descriptor with SAM_STAT_CHECK_CONDITION + cmd_kref.refcount = 0: struct qla_tgt_cmd { se_cmd = { scsi_status = 0x2 se_cmd_flags = 0x80090d, cmd_kref = { refcount = { counter = 0x0 } }, } The se_cmd_flags=0x80090d translation to enum se_cmd_flags_table: - SCF_TRANSPORT_TASK_SENSE - SCF_EMULATED_TASK_SENSE - SCF_SCSI_DATA_CDB - SCF_SE_LUN_CMD - SCF_SENT_CHECK_CONDITION - SCF_USE_CPUID Also, ->cmd_wait_comp has a zero rlock counter + dead magic: cmd_wait_comp = { done = 0x0, wait = { lock = { { rlock = { raw_lock = { val = { counter = 0x0 } }, magic = 0xdead4ead, owner_cpu = 0x, owner = 0x, > I can recreate this issue at will within 5 minute of triggering sg_reset > with following steps > > 1. Export 4 RAM disk LUNs on each of 2 port adapter. Initiator will see 8 > RAM disk targets > 2. Start IO with 4K block size and 8 threads with 80% write 20% read and > 100% dandom. > (I am using vdbench for generating IO. I can provide setup/config scr
[PATCH] bio: return EINTR if copying to user space got interrupted
Commit 35dc248383bbab0a7203fca4d722875bc81ef091 introduced a check for current->mm to see if we have a user space context and only copies data if we do. Now if an IO gets interrupted by a signal data isn't copied into user space any more (as we don't have a user space context) but user space isn't notified about it. This patch modifies the behaviour to return -EINTR from bio_uncopy_user() to notify userland that a signal has interrupted the syscall, otherwise it could lead to a situation where the caller may get a buffer with no data returned. This can be reproduced by issuing SG_IO ioctl()s in one thread while constantly sending signals to it. Fixes: 35dc248 [SCSI] sg: Fix user memory corruption when SG_IO is interrupted by a signal Signed-off-by: Johannes Thumshirn Signed-off-by: Hannes Reinecke Cc: sta...@vger.kernel.org # v.3.11+ --- block/bio.c | 7 +-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/block/bio.c b/block/bio.c index dbabd48..24e5b69 100644 --- a/block/bio.c +++ b/block/bio.c @@ -1090,9 +1090,12 @@ int bio_uncopy_user(struct bio *bio) if (!bio_flagged(bio, BIO_NULL_MAPPED)) { /* * if we're in a workqueue, the request is orphaned, so -* don't copy into a random user address space, just free. +* don't copy into a random user address space, just free +* and return -EINTR so user space doesn't expect any data. */ - if (current->mm && bio_data_dir(bio) == READ) + if (!current->mm) + ret = -EINTR; + else if (bio_data_dir(bio) == READ) ret = bio_copy_to_iter(bio, bmd->iter); if (bmd->is_our_pages) bio_free_pages(bio); -- 1.8.5.6 -- 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
[PATCHv6 12/23] scsi_dh_alua: remove 'rel_port' from alua_dh_data structure
The 'relative port' field is not used, and might get stale when the port group changes. So remove the field altogether. Reviewed-by: Christoph Hellwig Signed-off-by: Hannes Reinecke --- drivers/scsi/device_handler/scsi_dh_alua.c | 6 +- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 0212aee..78e6fa9 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -87,7 +87,6 @@ struct alua_port_group { struct alua_dh_data { struct alua_port_group *pg; int group_id; - int rel_port; struct scsi_device *sdev; activate_complete callback_fn; void*callback_data; @@ -325,12 +324,10 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h, return SCSI_DH_NOMEM; return SCSI_DH_DEV_UNSUPP; } - h->rel_port = rel_port; - sdev_printk(KERN_INFO, sdev, "%s: device %s port group %x rel port %x\n", ALUA_DH_NAME, h->pg->device_id_str, - h->group_id, h->rel_port); + h->group_id, rel_port); return alua_rtpg(sdev, h->pg); } @@ -764,7 +761,6 @@ static int alua_bus_attach(struct scsi_device *sdev) if (!h) return -ENOMEM; h->pg = NULL; - h->rel_port = -1; h->sdev = sdev; err = alua_initialize(sdev, h); -- 1.8.5.6 -- 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
[PATCHv6 07/23] scsi_dh_alua: Use separate alua_port_group structure
The port group needs to be a separate structure as several LUNs might belong to the same group. Reviewed-by: Christoph Hellwig Reviewed-by: Ewan Milne Signed-off-by: Hannes Reinecke --- drivers/scsi/device_handler/scsi_dh_alua.c | 181 - include/scsi/scsi_dh.h | 1 + 2 files changed, 129 insertions(+), 53 deletions(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 3b869a1..e25c622 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -64,14 +64,24 @@ #define ALUA_OPTIMIZE_STPG 1 #define ALUA_RTPG_EXT_HDR_UNSUPP 2 -struct alua_dh_data { +static LIST_HEAD(port_group_list); +static DEFINE_SPINLOCK(port_group_lock); + +struct alua_port_group { + struct kref kref; + struct list_headnode; int group_id; - int rel_port; int tpgs; int state; int pref; unsignedflags; /* used for optimizing STPG */ unsigned char transition_tmo; +}; + +struct alua_dh_data { + struct alua_port_group *pg; + int group_id; + int rel_port; struct scsi_device *sdev; activate_complete callback_fn; void*callback_data; @@ -82,6 +92,17 @@ struct alua_dh_data { static char print_alua_state(int); +static void release_port_group(struct kref *kref) +{ + struct alua_port_group *pg; + + pg = container_of(kref, struct alua_port_group, kref); + spin_lock(&port_group_lock); + list_del(&pg->node); + spin_unlock(&port_group_lock); + kfree(pg); +} + /* * submit_rtpg - Issue a REPORT TARGET GROUP STATES command * @sdev: sdev the command should be sent to @@ -142,6 +163,35 @@ static int submit_stpg(struct scsi_device *sdev, int group_id, } /* + * alua_alloc_pg - Allocate a new port_group structure + * @sdev: scsi device + * @h: alua device_handler data + * @group_id: port group id + * + * Allocate a new port_group structure for a given + * device. + */ +struct alua_port_group *alua_alloc_pg(struct scsi_device *sdev, + int group_id, int tpgs) +{ + struct alua_port_group *pg; + + pg = kzalloc(sizeof(struct alua_port_group), GFP_KERNEL); + if (!pg) + return NULL; + + pg->group_id = group_id; + pg->tpgs = tpgs; + pg->state = TPGS_STATE_OPTIMIZED; + kref_init(&pg->kref); + spin_lock(&port_group_lock); + list_add(&pg->node, &port_group_list); + spin_unlock(&port_group_lock); + + return pg; +} + +/* * alua_check_tpgs - Evaluate TPGS setting * @sdev: device to be checked * @@ -216,7 +266,6 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h) ALUA_DH_NAME); return SCSI_DH_DEV_UNSUPP; } - h->state = TPGS_STATE_OPTIMIZED; h->group_id = group_id; sdev_printk(KERN_INFO, sdev, @@ -312,7 +361,7 @@ static int alua_check_sense(struct scsi_device *sdev, * Returns SCSI_DH_DEV_OFFLINED if the path is * found to be unusable. */ -static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_for_transition) +static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg, int wait_for_transition) { struct scsi_sense_hdr sense_hdr; int len, k, off, valid_states = 0, bufflen = ALUA_RTPG_SIZE; @@ -322,17 +371,17 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_ unsigned int tpg_desc_tbl_off; unsigned char orig_transition_tmo; - if (!h->transition_tmo) + if (!pg->transition_tmo) expiry = round_jiffies_up(jiffies + ALUA_FAILOVER_TIMEOUT * HZ); else - expiry = round_jiffies_up(jiffies + h->transition_tmo * HZ); + expiry = round_jiffies_up(jiffies + pg->transition_tmo * HZ); buff = kzalloc(bufflen, GFP_KERNEL); if (!buff) return SCSI_DH_DEV_TEMP_BUSY; retry: - retval = submit_rtpg(sdev, buff, bufflen, &sense_hdr, h->flags); + retval = submit_rtpg(sdev, buff, bufflen, &sense_hdr, pg->flags); if (retval) { if (!scsi_sense_valid(&sense_hdr)) { @@ -353,10 +402,10 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_ * The retry without rtpg_ext_hdr_req set * handles this. */ - if (!(h->flags & ALUA_RTPG_EXT_HDR_UNSUPP) && + if (!(pg->flags & ALUA_RTPG_EXT_HDR_UNSUPP) && sense_hdr.sense_key == ILLEGAL_REQUEST && sense_hdr.as
[PATCHv6 20/23] scsi: Add 'access_state' attribute
Add an 'access_state' attribute to struct scsi_device to display the asymmetric LUN access state. Reviewed-by: Ewan Milne Reviewed-by: Christoph Hellwig Signed-off-by: Hannes Reinecke --- drivers/scsi/scsi_scan.c | 1 + drivers/scsi/scsi_sysfs.c | 49 ++ include/scsi/scsi_device.h | 1 + include/scsi/scsi_proto.h | 12 4 files changed, 63 insertions(+) diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 97074c9..5bf3945 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -231,6 +231,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget, sdev->lun = lun; sdev->channel = starget->channel; sdev->sdev_state = SDEV_CREATED; + sdev->access_state = SCSI_ACCESS_STATE_UNKNOWN; INIT_LIST_HEAD(&sdev->siblings); INIT_LIST_HEAD(&sdev->same_target_siblings); INIT_LIST_HEAD(&sdev->cmd_list); diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 4f18a85..e1541d5 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -81,6 +81,34 @@ const char *scsi_host_state_name(enum scsi_host_state state) return name; } +static const struct { + unsigned char value; + char*name; +} sdev_access_states[] = { + { SCSI_ACCESS_STATE_OPTIMAL, "active/optimized" }, + { SCSI_ACCESS_STATE_ACTIVE, "active/non-optimized" }, + { SCSI_ACCESS_STATE_STANDBY, "standby" }, + { SCSI_ACCESS_STATE_UNAVAILABLE, "unavailable" }, + { SCSI_ACCESS_STATE_LBA, "lba-dependent" }, + { SCSI_ACCESS_STATE_OFFLINE, "offline" }, + { SCSI_ACCESS_STATE_TRANSITIONING, "transitioning" }, + { SCSI_ACCESS_STATE_UNKNOWN, "unknown" }, +}; + +const char *scsi_access_state_name(unsigned char state) +{ + int i; + char *name = NULL; + + for (i = 0; i < ARRAY_SIZE(sdev_access_states); i++) { + if (sdev_access_states[i].value == state) { + name = sdev_access_states[i].name; + break; + } + } + return name; +} + static int check_set(unsigned long long *val, char *src) { char *last; @@ -973,6 +1001,26 @@ sdev_store_dh_state(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR(dh_state, S_IRUGO | S_IWUSR, sdev_show_dh_state, sdev_store_dh_state); + +static ssize_t +sdev_show_access_state(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct scsi_device *sdev = to_scsi_device(dev); + unsigned char access_state; + bool pref = false; + + if (sdev->access_state & SCSI_ACCESS_STATE_PREFERRED) + pref = true; + + access_state = (sdev->access_state & SCSI_ACCESS_STATE_MASK); + + return snprintf(buf, 32, "%s%s\n", + scsi_access_state_name(access_state), + pref ? " preferred" : ""); +} +static DEVICE_ATTR(access_state, S_IRUGO, sdev_show_access_state, NULL); #endif static ssize_t @@ -1047,6 +1095,7 @@ static struct attribute *scsi_sdev_attrs[] = { &dev_attr_wwid.attr, #ifdef CONFIG_SCSI_DH &dev_attr_dh_state.attr, + &dev_attr_access_state.attr, #endif &dev_attr_queue_ramp_up_period.attr, REF_EVT(media_change), diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 4af2b24..c067019 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -201,6 +201,7 @@ struct scsi_device { struct scsi_device_handler *handler; void*handler_data; + unsigned char access_state; enum scsi_device_state sdev_state; unsigned long sdev_data[0]; } __attribute__((aligned(sizeof(unsigned long; diff --git a/include/scsi/scsi_proto.h b/include/scsi/scsi_proto.h index a9fbf1b..683bf29 100644 --- a/include/scsi/scsi_proto.h +++ b/include/scsi/scsi_proto.h @@ -277,5 +277,17 @@ struct scsi_lun { __u8 scsi_lun[8]; }; +/* SPC asymmetric access states */ +#define SCSI_ACCESS_STATE_OPTIMAL 0x00 +#define SCSI_ACCESS_STATE_ACTIVE 0x01 +#define SCSI_ACCESS_STATE_STANDBY 0x02 +#define SCSI_ACCESS_STATE_UNAVAILABLE 0x03 +#define SCSI_ACCESS_STATE_LBA 0x04 +#define SCSI_ACCESS_STATE_OFFLINE 0x0e +#define SCSI_ACCESS_STATE_TRANSITIONING 0x0f + +#define SCSI_ACCESS_STATE_MASK0x0f +#define SCSI_ACCESS_STATE_PREFERRED 0x80 +#define SCSI_ACCESS_STATE_UNKNOWN 0x70 #endif /* _SCSI_PROTO_H_ */ -- 1.8.5.6 -- 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
[PATCHv6 10/23] revert commit a8e5a2d593cb ("[SCSI] scsi_dh_alua: ALUA handler attach should succeed while TPG is transitioning")
This reverts commit a8e5a2d593cbfccf530c3382c2c328d2edaa7b66 Obsoleted by the next patch. Reviewed-by: Christoph Hellwig Reviewed-by: Ewan Milne Signed-off-by: Hannes Reinecke --- drivers/scsi/device_handler/scsi_dh_alua.c | 31 -- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index a1bcad3..61c67e6 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -92,7 +92,7 @@ struct alua_dh_data { #define ALUA_POLICY_SWITCH_CURRENT 0 #define ALUA_POLICY_SWITCH_ALL 1 -static int alua_rtpg(struct scsi_device *, struct alua_port_group *, int); +static int alua_rtpg(struct scsi_device *, struct alua_port_group *); static char print_alua_state(int); static void release_port_group(struct kref *kref) @@ -326,7 +326,7 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h, ALUA_DH_NAME, h->pg->device_id_str, h->group_id, h->rel_port); - return alua_rtpg(sdev, h->pg, 0); + return alua_rtpg(sdev, h->pg); } static char print_alua_state(int state) @@ -409,13 +409,12 @@ static int alua_check_sense(struct scsi_device *sdev, /* * alua_rtpg - Evaluate REPORT TARGET GROUP STATES * @sdev: the device to be evaluated. - * @wait_for_transition: if nonzero, wait ALUA_FAILOVER_TIMEOUT seconds for device to exit transitioning state * * Evaluate the Target Port Group State. * Returns SCSI_DH_DEV_OFFLINED if the path is * found to be unusable. */ -static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg, int wait_for_transition) +static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg) { struct scsi_sense_hdr sense_hdr; int len, k, off, valid_states = 0, bufflen = ALUA_RTPG_SIZE; @@ -506,8 +505,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg, int w else pg->transition_tmo = ALUA_FAILOVER_TIMEOUT; - if (wait_for_transition && - (orig_transition_tmo != pg->transition_tmo)) { + if (orig_transition_tmo != pg->transition_tmo) { sdev_printk(KERN_INFO, sdev, "%s: transition timeout set to %d seconds\n", ALUA_DH_NAME, pg->transition_tmo); @@ -545,19 +543,14 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg, int w switch (pg->state) { case TPGS_STATE_TRANSITIONING: - if (wait_for_transition) { - if (time_before(jiffies, expiry)) { - /* State transition, retry */ - interval += 2000; - msleep(interval); - goto retry; - } - err = SCSI_DH_RETRY; - } else { - err = SCSI_DH_OK; + if (time_before(jiffies, expiry)) { + /* State transition, retry */ + interval += 2000; + msleep(interval); + goto retry; } - /* Transitioning time exceeded, set port to standby */ + err = SCSI_DH_RETRY; pg->state = TPGS_STATE_STANDBY; break; case TPGS_STATE_OFFLINE: @@ -715,14 +708,14 @@ static int alua_activate(struct scsi_device *sdev, if (optimize_stpg) h->pg->flags |= ALUA_OPTIMIZE_STPG; - err = alua_rtpg(sdev, h->pg, 1); + err = alua_rtpg(sdev, h->pg); if (err != SCSI_DH_OK) { kref_put(&h->pg->kref, release_port_group); goto out; } err = alua_stpg(sdev, h->pg); if (err == SCSI_DH_RETRY) - err = alua_rtpg(sdev, h->pg, 1); + err = alua_rtpg(sdev, h->pg); kref_put(&h->pg->kref, release_port_group); out: if (fn) -- 1.8.5.6 -- 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
[PATCHv6 14/23] scsi_dh_alua: Allow workqueue to run synchronously
Some arrays may only capable of handling one STPG at a time, so this patch adds a singlethreaded workqueue for STPGs to be submitted synchronously. Reviewed-by: Christoph Hellwig Signed-off-by: Hannes Reinecke --- drivers/scsi/device_handler/scsi_dh_alua.c | 21 ++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index ede850b..43bf6ac 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -64,6 +64,7 @@ /* device handler flags */ #define ALUA_OPTIMIZE_STPG 0x01 #define ALUA_RTPG_EXT_HDR_UNSUPP 0x02 +#define ALUA_SYNC_STPG 0x04 /* State machine flags */ #define ALUA_PG_RUN_RTPG 0x10 #define ALUA_PG_RUN_STPG 0x20 @@ -76,6 +77,7 @@ MODULE_PARM_DESC(optimize_stpg, "Allow use of a non-optimized path, rather than static LIST_HEAD(port_group_list); static DEFINE_SPINLOCK(port_group_lock); static struct workqueue_struct *kaluad_wq; +static struct workqueue_struct *kaluad_sync_wq; struct alua_port_group { struct kref kref; @@ -688,6 +690,7 @@ static void alua_rtpg_work(struct work_struct *work) int err = SCSI_DH_OK; struct alua_queue_data *qdata, *tmp; unsigned long flags; + struct workqueue_struct *alua_wq = kaluad_wq; spin_lock_irqsave(&pg->lock, flags); sdev = pg->rtpg_sdev; @@ -697,6 +700,8 @@ static void alua_rtpg_work(struct work_struct *work) spin_unlock_irqrestore(&pg->lock, flags); return; } + if (pg->flags & ALUA_SYNC_STPG) + alua_wq = kaluad_sync_wq; pg->flags |= ALUA_PG_RUNNING; if (pg->flags & ALUA_PG_RUN_RTPG) { pg->flags &= ~ALUA_PG_RUN_RTPG; @@ -707,7 +712,7 @@ static void alua_rtpg_work(struct work_struct *work) pg->flags &= ~ALUA_PG_RUNNING; pg->flags |= ALUA_PG_RUN_RTPG; spin_unlock_irqrestore(&pg->lock, flags); - queue_delayed_work(kaluad_wq, &pg->rtpg_work, + queue_delayed_work(alua_wq, &pg->rtpg_work, pg->interval * HZ); return; } @@ -724,7 +729,7 @@ static void alua_rtpg_work(struct work_struct *work) pg->interval = 0; pg->flags &= ~ALUA_PG_RUNNING; spin_unlock_irqrestore(&pg->lock, flags); - queue_delayed_work(kaluad_wq, &pg->rtpg_work, + queue_delayed_work(alua_wq, &pg->rtpg_work, pg->interval * HZ); return; } @@ -753,6 +758,7 @@ static void alua_rtpg_queue(struct alua_port_group *pg, { int start_queue = 0; unsigned long flags; + struct workqueue_struct *alua_wq = kaluad_wq; if (!pg) return; @@ -770,10 +776,12 @@ static void alua_rtpg_queue(struct alua_port_group *pg, scsi_device_get(sdev); start_queue = 1; } + if (pg->flags & ALUA_SYNC_STPG) + alua_wq = kaluad_sync_wq; spin_unlock_irqrestore(&pg->lock, flags); if (start_queue && - !queue_delayed_work(kaluad_wq, &pg->rtpg_work, + !queue_delayed_work(alua_wq, &pg->rtpg_work, msecs_to_jiffies(ALUA_RTPG_DELAY_MSECS))) { scsi_device_put(sdev); kref_put(&pg->kref, release_port_group); @@ -992,10 +1000,16 @@ static int __init alua_init(void) /* Temporary failure, bypass */ return SCSI_DH_DEV_TEMP_BUSY; } + kaluad_sync_wq = create_workqueue("kaluad_sync"); + if (!kaluad_sync_wq) { + destroy_workqueue(kaluad_wq); + return SCSI_DH_DEV_TEMP_BUSY; + } r = scsi_register_device_handler(&alua_dh); if (r != 0) { printk(KERN_ERR "%s: Failed to register scsi device handler", ALUA_DH_NAME); + destroy_workqueue(kaluad_sync_wq); destroy_workqueue(kaluad_wq); } return r; @@ -1004,6 +1018,7 @@ static int __init alua_init(void) static void __exit alua_exit(void) { scsi_unregister_device_handler(&alua_dh); + destroy_workqueue(kaluad_sync_wq); destroy_workqueue(kaluad_wq); } -- 1.8.5.6 -- 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
[PATCHv6 04/23] scsi_dh_alua: call alua_rtpg() if stpg fails
If the call to SET TARGET PORT GROUPS fails we have no idea what state the array is left in, so we need to issue a call to REPORT TARGET PORT GROUPS in these cases. Reviewed-by: Christoph Hellwig Signed-off-by: Hannes Reinecke --- drivers/scsi/device_handler/scsi_dh_alua.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index ceca554..77e23a4 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -676,6 +676,8 @@ static int alua_activate(struct scsi_device *sdev, h->flags |= ALUA_OPTIMIZE_STPG; err = alua_stpg(sdev, h); + if (err == SCSI_DH_RETRY) + err = alua_rtpg(sdev, h, 1); out: if (fn) fn(data, err); -- 1.8.5.6 -- 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
[PATCHv6 23/23] scsi_dh_alua: Update version to 2.0
Reviewed-by: Christoph Hellwig Signed-off-by: Hannes Reinecke --- drivers/scsi/device_handler/scsi_dh_alua.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index cbbd957..e6cb225 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -30,7 +30,7 @@ #include #define ALUA_DH_NAME "alua" -#define ALUA_DH_VER "1.3" +#define ALUA_DH_VER "2.0" #define TPGS_SUPPORT_NONE 0x00 #define TPGS_SUPPORT_OPTIMIZED 0x01 -- 1.8.5.6 -- 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
[PATCHv6 21/23] scsi_dh_alua: use common definitions for ALUA state
scsi_proto.h now contains definitions for the ALUA state, so we don't have to carry them in the device handler. Reviewed-by: Christoph Hellwig Signed-off-by: Hannes Reinecke --- drivers/scsi/device_handler/scsi_dh_alua.c | 58 +- 1 file changed, 25 insertions(+), 33 deletions(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index c2841c4..b429ba3 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -31,14 +31,6 @@ #define ALUA_DH_NAME "alua" #define ALUA_DH_VER "1.3" -#define TPGS_STATE_OPTIMIZED 0x0 -#define TPGS_STATE_NONOPTIMIZED0x1 -#define TPGS_STATE_STANDBY 0x2 -#define TPGS_STATE_UNAVAILABLE 0x3 -#define TPGS_STATE_LBA_DEPENDENT 0x4 -#define TPGS_STATE_OFFLINE 0xe -#define TPGS_STATE_TRANSITIONING 0xf - #define TPGS_SUPPORT_NONE 0x00 #define TPGS_SUPPORT_OPTIMIZED 0x01 #define TPGS_SUPPORT_NONOPTIMIZED 0x02 @@ -180,7 +172,7 @@ static int submit_stpg(struct scsi_device *sdev, int group_id, /* Prepare the data buffer */ memset(stpg_data, 0, stpg_len); - stpg_data[4] = TPGS_STATE_OPTIMIZED & 0x0f; + stpg_data[4] = SCSI_ACCESS_STATE_OPTIMAL & 0x0f; put_unaligned_be16(group_id, &stpg_data[6]); /* Prepare the command. */ @@ -248,7 +240,7 @@ struct alua_port_group *alua_alloc_pg(struct scsi_device *sdev, } pg->group_id = group_id; pg->tpgs = tpgs; - pg->state = TPGS_STATE_OPTIMIZED; + pg->state = SCSI_ACCESS_STATE_OPTIMAL; if (optimize_stpg) pg->flags |= ALUA_OPTIMIZE_STPG; kref_init(&pg->kref); @@ -378,22 +370,22 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h, return SCSI_DH_OK; } -static char print_alua_state(int state) +static char print_alua_state(unsigned char state) { switch (state) { - case TPGS_STATE_OPTIMIZED: + case SCSI_ACCESS_STATE_OPTIMAL: return 'A'; - case TPGS_STATE_NONOPTIMIZED: + case SCSI_ACCESS_STATE_ACTIVE: return 'N'; - case TPGS_STATE_STANDBY: + case SCSI_ACCESS_STATE_STANDBY: return 'S'; - case TPGS_STATE_UNAVAILABLE: + case SCSI_ACCESS_STATE_UNAVAILABLE: return 'U'; - case TPGS_STATE_LBA_DEPENDENT: + case SCSI_ACCESS_STATE_LBA: return 'L'; - case TPGS_STATE_OFFLINE: + case SCSI_ACCESS_STATE_OFFLINE: return 'O'; - case TPGS_STATE_TRANSITIONING: + case SCSI_ACCESS_STATE_TRANSITIONING: return 'T'; default: return 'X'; @@ -647,7 +639,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg) valid_states&TPGS_SUPPORT_OPTIMIZED?'A':'a'); switch (pg->state) { - case TPGS_STATE_TRANSITIONING: + case SCSI_ACCESS_STATE_TRANSITIONING: if (time_before(jiffies, pg->expiry)) { /* State transition, retry */ pg->interval = 2; @@ -655,11 +647,11 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg) } else { /* Transitioning time exceeded, set port to standby */ err = SCSI_DH_IO; - pg->state = TPGS_STATE_STANDBY; + pg->state = SCSI_ACCESS_STATE_STANDBY; pg->expiry = 0; } break; - case TPGS_STATE_OFFLINE: + case SCSI_ACCESS_STATE_OFFLINE: /* Path unusable */ err = SCSI_DH_DEV_OFFLINED; pg->expiry = 0; @@ -693,21 +685,21 @@ static unsigned alua_stpg(struct scsi_device *sdev, struct alua_port_group *pg) return SCSI_DH_RETRY; } switch (pg->state) { - case TPGS_STATE_OPTIMIZED: + case SCSI_ACCESS_STATE_OPTIMAL: return SCSI_DH_OK; - case TPGS_STATE_NONOPTIMIZED: + case SCSI_ACCESS_STATE_ACTIVE: if ((pg->flags & ALUA_OPTIMIZE_STPG) && !pg->pref && (pg->tpgs & TPGS_MODE_IMPLICIT)) return SCSI_DH_OK; break; - case TPGS_STATE_STANDBY: - case TPGS_STATE_UNAVAILABLE: + case SCSI_ACCESS_STATE_STANDBY: + case SCSI_ACCESS_STATE_UNAVAILABLE: break; - case TPGS_STATE_OFFLINE: + case SCSI_ACCESS_STATE_OFFLINE: return SCSI_DH_IO; break; - case TPGS_STATE_TRANSITIONING: + case SCSI_ACCESS_STATE_TRANSITIONING: break; default: sdev_printk(KERN_INFO, sdev, @@ -762,7 +754,7 @@ static void alua_rtpg_work(struct work_struct *work)
[PATCHv6 01/23] scsi_dh_alua: Pass buffer as function argument
Pass in the buffer as a function argument for submit_rtpg(). Reviewed-by: Martin K. Petersen Reviewed-by: Christoph Hellwig Reviewed-by: Bart Van Assche Signed-off-by: Hannes Reinecke --- drivers/scsi/device_handler/scsi_dh_alua.c | 13 +++-- 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 5a328bf..df71e85 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -135,12 +135,13 @@ static struct request *get_alua_req(struct scsi_device *sdev, * submit_rtpg - Issue a REPORT TARGET GROUP STATES command * @sdev: sdev the command should be sent to */ -static unsigned submit_rtpg(struct scsi_device *sdev, struct alua_dh_data *h) +static unsigned submit_rtpg(struct scsi_device *sdev, unsigned char *buff, + int bufflen, unsigned char *sense, int flags) { struct request *rq; int err = 0; - rq = get_alua_req(sdev, h->buff, h->bufflen, READ); + rq = get_alua_req(sdev, buff, bufflen, READ); if (!rq) { err = DRIVER_BUSY << 24; goto done; @@ -148,14 +149,14 @@ static unsigned submit_rtpg(struct scsi_device *sdev, struct alua_dh_data *h) /* Prepare the command. */ rq->cmd[0] = MAINTENANCE_IN; - if (!(h->flags & ALUA_RTPG_EXT_HDR_UNSUPP)) + if (!(flags & ALUA_RTPG_EXT_HDR_UNSUPP)) rq->cmd[1] = MI_REPORT_TARGET_PGS | MI_EXT_HDR_PARAM_FMT; else rq->cmd[1] = MI_REPORT_TARGET_PGS; - put_unaligned_be32(h->bufflen, &rq->cmd[6]); + put_unaligned_be32(bufflen, &rq->cmd[6]); rq->cmd_len = COMMAND_SIZE(MAINTENANCE_IN); - rq->sense = h->sense; + rq->sense = sense; memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); rq->sense_len = 0; @@ -446,7 +447,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_ expiry = round_jiffies_up(jiffies + h->transition_tmo * HZ); retry: - retval = submit_rtpg(sdev, h); + retval = submit_rtpg(sdev, h->buff, h->bufflen, h->sense, h->flags); if (retval) { if (!scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE, &sense_hdr)) { -- 1.8.5.6 -- 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
[PATCHv6 06/23] scsi_dh_alua: allocate RTPG buffer separately
The RTPG buffer will only evaluated within alua_rtpg(), so we can allocate it locally there and avoid having to put it into the global structure. Reviewed-by: Ewan Milne Reviewed-by: Christoph Hellwig Signed-off-by: Hannes Reinecke --- drivers/scsi/device_handler/scsi_dh_alua.c | 57 -- 1 file changed, 23 insertions(+), 34 deletions(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 2101518..3b869a1 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -56,7 +56,7 @@ #define TPGS_MODE_IMPLICIT 0x1 #define TPGS_MODE_EXPLICIT 0x2 -#define ALUA_INQUIRY_SIZE 36 +#define ALUA_RTPG_SIZE 128 #define ALUA_FAILOVER_TIMEOUT 60 #define ALUA_FAILOVER_RETRIES 5 @@ -71,9 +71,6 @@ struct alua_dh_data { int state; int pref; unsignedflags; /* used for optimizing STPG */ - unsigned char inq[ALUA_INQUIRY_SIZE]; - unsigned char *buff; - int bufflen; unsigned char transition_tmo; struct scsi_device *sdev; activate_complete callback_fn; @@ -85,21 +82,6 @@ struct alua_dh_data { static char print_alua_state(int); -static int realloc_buffer(struct alua_dh_data *h, unsigned len) -{ - if (h->buff && h->buff != h->inq) - kfree(h->buff); - - h->buff = kmalloc(len, GFP_NOIO); - if (!h->buff) { - h->buff = h->inq; - h->bufflen = ALUA_INQUIRY_SIZE; - return 1; - } - h->bufflen = len; - return 0; -} - /* * submit_rtpg - Issue a REPORT TARGET GROUP STATES command * @sdev: sdev the command should be sent to @@ -333,8 +315,8 @@ static int alua_check_sense(struct scsi_device *sdev, static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_for_transition) { struct scsi_sense_hdr sense_hdr; - int len, k, off, valid_states = 0; - unsigned char *ucp; + int len, k, off, valid_states = 0, bufflen = ALUA_RTPG_SIZE; + unsigned char *ucp, *buff; unsigned err, retval; unsigned long expiry, interval = 0; unsigned int tpg_desc_tbl_off; @@ -345,14 +327,19 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_ else expiry = round_jiffies_up(jiffies + h->transition_tmo * HZ); + buff = kzalloc(bufflen, GFP_KERNEL); + if (!buff) + return SCSI_DH_DEV_TEMP_BUSY; + retry: - retval = submit_rtpg(sdev, h->buff, h->bufflen, &sense_hdr, h->flags); + retval = submit_rtpg(sdev, buff, bufflen, &sense_hdr, h->flags); if (retval) { if (!scsi_sense_valid(&sense_hdr)) { sdev_printk(KERN_INFO, sdev, "%s: rtpg failed, result %d\n", ALUA_DH_NAME, retval); + kfree(buff); if (driver_byte(retval) == DRIVER_ERROR) return SCSI_DH_DEV_TEMP_BUSY; return SCSI_DH_IO; @@ -390,14 +377,18 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_ sdev_printk(KERN_ERR, sdev, "%s: rtpg failed\n", ALUA_DH_NAME); scsi_print_sense_hdr(sdev, ALUA_DH_NAME, &sense_hdr); + kfree(buff); return SCSI_DH_IO; } - len = get_unaligned_be32(&h->buff[0]) + 4; + len = get_unaligned_be32(&buff[0]) + 4; - if (len > h->bufflen) { + if (len > bufflen) { /* Resubmit with the correct length */ - if (realloc_buffer(h, len)) { + kfree(buff); + bufflen = len; + buff = kmalloc(bufflen, GFP_KERNEL); + if (!buff) { sdev_printk(KERN_WARNING, sdev, "%s: kmalloc buffer failed\n",__func__); /* Temporary failure, bypass */ @@ -407,24 +398,25 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_ } orig_transition_tmo = h->transition_tmo; - if ((h->buff[4] & RTPG_FMT_MASK) == RTPG_FMT_EXT_HDR && h->buff[5] != 0) - h->transition_tmo = h->buff[5]; + if ((buff[4] & RTPG_FMT_MASK) == RTPG_FMT_EXT_HDR && buff[5] != 0) + h->transition_tmo = buff[5]; else h->transition_tmo = ALUA_FAILOVER_TIMEOUT; - if (wait_for_transition && (orig_transition_tmo != h->transition_tmo)) { + if (wait_for_transition && + (orig_transition_tmo != h->transition_tmo)) { sdev_printk(KERN_INFO, s
[PATCHv6 13/23] scsi_dh_alua: Use workqueue for RTPG
The current ALUA device_handler has two drawbacks: - We're sending a 'SET TARGET PORT GROUP' command to every LUN, disregarding the fact that several LUNs might be in a port group and will be automatically switched whenever _any_ LUN within that port group receives the command. - Whenever a LUN is in 'transitioning' mode we cannot block I/O to that LUN, instead the controller has to abort the command. This leads to increased traffic across the wire and heavy load on the controller during switchover. With this patch the RTPG handling is moved to a per-portgroup workqueue. This reduces the number of 'REPORT TARGET PORT GROUP' and 'SET TARGET PORT GROUPS' sent to the controller as we're sending them now per port group, and not per device as previously. It also allows us to block I/O to any LUN / port group found to be in 'transitioning' ALUA mode, as the workqueue item will be requeued until the controller moves out of transitioning. Reviewed-by: Christoph Hellwig Signed-off-by: Hannes Reinecke --- drivers/scsi/device_handler/scsi_dh_alua.c | 296 +++-- 1 file changed, 242 insertions(+), 54 deletions(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 78e6fa9..ede850b 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -59,10 +59,15 @@ #define ALUA_RTPG_SIZE 128 #define ALUA_FAILOVER_TIMEOUT 60 #define ALUA_FAILOVER_RETRIES 5 +#define ALUA_RTPG_DELAY_MSECS 5 /* device handler flags */ -#define ALUA_OPTIMIZE_STPG 1 -#define ALUA_RTPG_EXT_HDR_UNSUPP 2 +#define ALUA_OPTIMIZE_STPG 0x01 +#define ALUA_RTPG_EXT_HDR_UNSUPP 0x02 +/* State machine flags */ +#define ALUA_PG_RUN_RTPG 0x10 +#define ALUA_PG_RUN_STPG 0x20 +#define ALUA_PG_RUNNING0x40 static uint optimize_stpg; module_param(optimize_stpg, uint, S_IRUGO|S_IWUSR); @@ -70,9 +75,11 @@ MODULE_PARM_DESC(optimize_stpg, "Allow use of a non-optimized path, rather than static LIST_HEAD(port_group_list); static DEFINE_SPINLOCK(port_group_lock); +static struct workqueue_struct *kaluad_wq; struct alua_port_group { struct kref kref; + struct rcu_head rcu; struct list_headnode; unsigned char device_id_str[256]; int device_id_len; @@ -82,12 +89,25 @@ struct alua_port_group { int pref; unsignedflags; /* used for optimizing STPG */ unsigned char transition_tmo; + unsigned long expiry; + unsigned long interval; + struct delayed_work rtpg_work; + spinlock_t lock; + struct list_headrtpg_list; + struct scsi_device *rtpg_sdev; }; struct alua_dh_data { struct alua_port_group *pg; int group_id; + spinlock_t pg_lock; struct scsi_device *sdev; + int init_error; + struct mutexinit_mutex; +}; + +struct alua_queue_data { + struct list_headentry; activate_complete callback_fn; void*callback_data; }; @@ -95,18 +115,22 @@ struct alua_dh_data { #define ALUA_POLICY_SWITCH_CURRENT 0 #define ALUA_POLICY_SWITCH_ALL 1 -static int alua_rtpg(struct scsi_device *, struct alua_port_group *); -static char print_alua_state(int); +static void alua_rtpg_work(struct work_struct *work); +static void alua_rtpg_queue(struct alua_port_group *pg, + struct scsi_device *sdev, + struct alua_queue_data *qdata); static void release_port_group(struct kref *kref) { struct alua_port_group *pg; pg = container_of(kref, struct alua_port_group, kref); + if (pg->rtpg_sdev) + flush_delayed_work(&pg->rtpg_work); spin_lock(&port_group_lock); list_del(&pg->node); spin_unlock(&port_group_lock); - kfree(pg); + kfree_rcu(pg, rcu); } /* @@ -225,6 +249,10 @@ struct alua_port_group *alua_alloc_pg(struct scsi_device *sdev, if (optimize_stpg) pg->flags |= ALUA_OPTIMIZE_STPG; kref_init(&pg->kref); + INIT_DELAYED_WORK(&pg->rtpg_work, alua_rtpg_work); + INIT_LIST_HEAD(&pg->rtpg_list); + INIT_LIST_HEAD(&pg->node); + spin_lock_init(&pg->lock); spin_lock(&port_group_lock); tmp_pg = alua_find_get_pg(pg->device_id_str, pg->device_id_len, @@ -304,6 +332,7 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h, int tpgs) { int rel_port = -1, group_id; + struct alua_port_group *pg, *old_pg = NULL; group_id = scsi_vpd_tpg_id(sdev, &re
[PATCHv6 19/23] scsi_dh: add 'rescan' callback
If a device needs to be rescanned the device_handler might need to be rechecked, too. So add a 'rescan' callback to the device handler and call it upon scsi_rescan_device(). The rescan callback will be invoked from the Unit Attention handling of ASC/ASCQ 3F 03 (INQUIRY DATA HAS CHANGED). Reviewed-by: Christoph Hellwig Signed-off-by: Hannes Reinecke --- drivers/scsi/device_handler/scsi_dh_alua.c | 8 drivers/scsi/scsi_lib.c| 1 + drivers/scsi/scsi_scan.c | 8 +++- include/scsi/scsi_dh.h | 1 + 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 35ad81f..c2841c4 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -1037,6 +1037,13 @@ static int alua_prep_fn(struct scsi_device *sdev, struct request *req) } +static void alua_rescan(struct scsi_device *sdev) +{ + struct alua_dh_data *h = sdev->handler_data; + + alua_initialize(sdev, h); +} + /* * alua_bus_attach - Attach device handler * @sdev: device to be attached to @@ -1097,6 +1104,7 @@ static struct scsi_device_handler alua_dh = { .prep_fn = alua_prep_fn, .check_sense = alua_check_sense, .activate = alua_activate, + .rescan = alua_rescan, .set_params = alua_set_params, }; diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index fa6b2c4..d46193a 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -2699,6 +2699,7 @@ static void scsi_evt_emit(struct scsi_device *sdev, struct scsi_event *evt) envp[idx++] = "SDEV_MEDIA_CHANGE=1"; break; case SDEV_EVT_INQUIRY_CHANGE_REPORTED: + scsi_rescan_device(&sdev->sdev_gendev); envp[idx++] = "SDEV_UA=INQUIRY_DATA_HAS_CHANGED"; break; case SDEV_EVT_CAPACITY_CHANGE_REPORTED: diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 420239c..97074c9 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include "scsi_priv.h" @@ -1524,9 +1525,14 @@ EXPORT_SYMBOL(scsi_add_device); void scsi_rescan_device(struct device *dev) { + struct scsi_device *sdev = to_scsi_device(dev); + device_lock(dev); - scsi_attach_vpd(to_scsi_device(dev)); + scsi_attach_vpd(sdev); + + if (sdev->handler && sdev->handler->rescan) + sdev->handler->rescan(sdev); if (dev->driver && try_module_get(dev->driver->owner)) { struct scsi_driver *drv = to_scsi_driver(dev->driver); diff --git a/include/scsi/scsi_dh.h b/include/scsi/scsi_dh.h index 7e184c6..c7bba2b 100644 --- a/include/scsi/scsi_dh.h +++ b/include/scsi/scsi_dh.h @@ -71,6 +71,7 @@ struct scsi_device_handler { int (*activate)(struct scsi_device *, activate_complete, void *); int (*prep_fn)(struct scsi_device *, struct request *); int (*set_params)(struct scsi_device *, const char *); + void (*rescan)(struct scsi_device *); }; #ifdef CONFIG_SCSI_DH -- 1.8.5.6 -- 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
[PATCHv6 08/23] scsi_dh_alua: use unique device id
Use scsi_vpd_lun_id() to assign a unique device identification to the alua port group structure. Reviewed-by: Christoph Hellwig Signed-off-by: Hannes Reinecke --- drivers/scsi/device_handler/scsi_dh_alua.c | 55 +++--- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index e25c622..0262085 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -70,6 +70,8 @@ static DEFINE_SPINLOCK(port_group_lock); struct alua_port_group { struct kref kref; struct list_headnode; + unsigned char device_id_str[256]; + int device_id_len; int group_id; int tpgs; int state; @@ -162,6 +164,26 @@ static int submit_stpg(struct scsi_device *sdev, int group_id, ALUA_FAILOVER_RETRIES, NULL, req_flags); } +struct alua_port_group *alua_find_get_pg(char *id_str, size_t id_size, +int group_id) +{ + struct alua_port_group *pg; + + list_for_each_entry(pg, &port_group_list, node) { + if (pg->group_id != group_id) + continue; + if (pg->device_id_len != id_size) + continue; + if (strncmp(pg->device_id_str, id_str, id_size)) + continue; + if (!kref_get_unless_zero(&pg->kref)) + continue; + return pg; + } + + return NULL; +} + /* * alua_alloc_pg - Allocate a new port_group structure * @sdev: scsi device @@ -174,17 +196,39 @@ static int submit_stpg(struct scsi_device *sdev, int group_id, struct alua_port_group *alua_alloc_pg(struct scsi_device *sdev, int group_id, int tpgs) { - struct alua_port_group *pg; + struct alua_port_group *pg, *tmp_pg; pg = kzalloc(sizeof(struct alua_port_group), GFP_KERNEL); if (!pg) - return NULL; + return ERR_PTR(-ENOMEM); + pg->device_id_len = scsi_vpd_lun_id(sdev, pg->device_id_str, + sizeof(pg->device_id_str)); + if (pg->device_id_len <= 0) { + /* +* Internal error: TPGS supported but no device +* identifcation found. Disable ALUA support. +*/ + kfree(pg); + sdev_printk(KERN_INFO, sdev, + "%s: No device descriptors found\n", + ALUA_DH_NAME); + return ERR_PTR(-ENXIO); + } pg->group_id = group_id; pg->tpgs = tpgs; pg->state = TPGS_STATE_OPTIMIZED; kref_init(&pg->kref); + spin_lock(&port_group_lock); + tmp_pg = alua_find_get_pg(pg->device_id_str, pg->device_id_len, + group_id); + if (tmp_pg) { + spin_unlock(&port_group_lock); + kfree(pg); + return tmp_pg; + } + list_add(&pg->node, &port_group_list); spin_unlock(&port_group_lock); @@ -269,7 +313,7 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h) h->group_id = group_id; sdev_printk(KERN_INFO, sdev, - "%s: port group %02x rel port %02x\n", + "%s: port group %x rel port %x\n", ALUA_DH_NAME, h->group_id, h->rel_port); return 0; @@ -599,8 +643,9 @@ static int alua_initialize(struct scsi_device *sdev, struct alua_dh_data *h) goto out; h->pg = alua_alloc_pg(sdev, h->group_id, tpgs); - if (!h->pg) { - err = SCSI_DH_NOMEM; + if (IS_ERR(h->pg)) { + if (PTR_ERR(h->pg) == -ENOMEM) + err = SCSI_DH_NOMEM; goto out; } kref_get(&h->pg->kref); -- 1.8.5.6 -- 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
[PATCHv6 22/23] scsi_dh_alua: update 'access_state' field
Track attached SCSI devices and update the 'access_state' field whenever an ALUA state change has been detected. Reviewed-by: Ewan Milne Reviewed-by: Christoph Hellwig Signed-off-by: Hannes Reinecke --- drivers/scsi/device_handler/scsi_dh_alua.c | 48 -- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index b429ba3..cbbd957 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -75,6 +76,7 @@ struct alua_port_group { struct kref kref; struct rcu_head rcu; struct list_headnode; + struct list_headdh_list; unsigned char device_id_str[256]; int device_id_len; int group_id; @@ -92,6 +94,7 @@ struct alua_port_group { }; struct alua_dh_data { + struct list_headnode; struct alua_port_group *pg; int group_id; spinlock_t pg_lock; @@ -247,6 +250,7 @@ struct alua_port_group *alua_alloc_pg(struct scsi_device *sdev, INIT_DELAYED_WORK(&pg->rtpg_work, alua_rtpg_work); INIT_LIST_HEAD(&pg->rtpg_list); INIT_LIST_HEAD(&pg->node); + INIT_LIST_HEAD(&pg->dh_list); spin_lock_init(&pg->lock); spin_lock(&port_group_lock); @@ -328,6 +332,8 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h, { int rel_port = -1, group_id; struct alua_port_group *pg, *old_pg = NULL; + bool pg_updated; + unsigned long flags; group_id = scsi_vpd_tpg_id(sdev, &rel_port); if (group_id < 0) { @@ -357,13 +363,25 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h, old_pg = h->pg; if (old_pg != pg) { /* port group has changed. Update to new port group */ + if (h->pg) { + spin_lock_irqsave(&old_pg->lock, flags); + list_del_rcu(&h->node); + spin_unlock_irqrestore(&old_pg->lock, flags); + } rcu_assign_pointer(h->pg, pg); + pg_updated = true; } if (sdev->synchronous_alua) pg->flags |= ALUA_SYNC_STPG; alua_rtpg_queue(h->pg, sdev, NULL, true); spin_unlock(&h->pg_lock); + if (pg_updated) { + spin_lock_irqsave(&pg->lock, flags); + list_add_rcu(&h->node, &pg->dh_list); + spin_unlock_irqrestore(&pg->lock, flags); + } + if (old_pg) kref_put(&old_pg->kref, release_port_group); @@ -613,8 +631,18 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg) if (spin_trylock_irqsave(&tmp_pg->lock, flags)) { if ((tmp_pg == pg) || !(tmp_pg->flags & ALUA_PG_RUNNING)) { + struct alua_dh_data *h; + tmp_pg->state = desc[0] & 0x0f; tmp_pg->pref = desc[0] >> 7; + rcu_read_lock(); + list_for_each_entry_rcu(h, + &tmp_pg->dh_list, node) { + /* h->sdev should always be valid */ + BUG_ON(!h->sdev); + h->sdev->access_state = desc[0]; + } + rcu_read_unlock(); } if (tmp_pg == pg) valid_states = desc[1]; @@ -645,10 +673,22 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg) pg->interval = 2; err = SCSI_DH_RETRY; } else { + struct alua_dh_data *h; + /* Transitioning time exceeded, set port to standby */ err = SCSI_DH_IO; pg->state = SCSI_ACCESS_STATE_STANDBY; pg->expiry = 0; + rcu_read_lock(); + list_for_each_entry_rcu(h, &pg->dh_list, node) { + BUG_ON(!h->sdev); + h->sdev->access_state = + (pg->state & SCSI_ACCESS_STATE_MASK); + if (pg->pref) + h->sdev->access_state |= +
[PATCHv6 18/23] scsi_dh_alua: Send TEST UNIT READY to poll for transitioning
Sending a 'REPORT TARGET PORT GROUP' command is a costly operation, as the array has to gather information about all ports. So instead of using RTPG to poll for a status update when a port is in transitioning we should be sending a TEST UNIT READY, and wait for the sense code to report success. Signed-off-by: Hannes Reinecke Reviewed-by: Ewan Milne Reviewed-by: Christoph Hellwig --- drivers/scsi/device_handler/scsi_dh_alua.c | 38 ++ 1 file changed, 38 insertions(+) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index ed77b7c..35ad81f 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -466,6 +466,30 @@ static int alua_check_sense(struct scsi_device *sdev, } /* + * alua_tur - Send a TEST UNIT READY + * @sdev: device to which the TEST UNIT READY command should be send + * + * Send a TEST UNIT READY to @sdev to figure out the device state + * Returns SCSI_DH_RETRY if the sense code is NOT READY/ALUA TRANSITIONING, + * SCSI_DH_OK if no error occurred, and SCSI_DH_IO otherwise. + */ +static int alua_tur(struct scsi_device *sdev) +{ + struct scsi_sense_hdr sense_hdr; + int retval; + + retval = scsi_test_unit_ready(sdev, ALUA_FAILOVER_TIMEOUT * HZ, + ALUA_FAILOVER_RETRIES, &sense_hdr); + if (sense_hdr.sense_key == NOT_READY && + sense_hdr.asc == 0x04 && sense_hdr.ascq == 0x0a) + return SCSI_DH_RETRY; + else if (retval) + return SCSI_DH_IO; + else + return SCSI_DH_OK; +} + +/* * alua_rtpg - Evaluate REPORT TARGET GROUP STATES * @sdev: the device to be evaluated. * @@ -734,8 +758,22 @@ static void alua_rtpg_work(struct work_struct *work) alua_wq = kaluad_sync_wq; pg->flags |= ALUA_PG_RUNNING; if (pg->flags & ALUA_PG_RUN_RTPG) { + int state = pg->state; + pg->flags &= ~ALUA_PG_RUN_RTPG; spin_unlock_irqrestore(&pg->lock, flags); + if (state == TPGS_STATE_TRANSITIONING) { + if (alua_tur(sdev) == SCSI_DH_RETRY) { + spin_lock_irqsave(&pg->lock, flags); + pg->flags &= ~ALUA_PG_RUNNING; + pg->flags |= ALUA_PG_RUN_RTPG; + spin_unlock_irqrestore(&pg->lock, flags); + queue_delayed_work(alua_wq, &pg->rtpg_work, + pg->interval * HZ); + return; + } + /* Send RTPG on failure or if TUR indicates SUCCESS */ + } err = alua_rtpg(sdev, pg); spin_lock_irqsave(&pg->lock, flags); if (err == SCSI_DH_RETRY || pg->flags & ALUA_PG_RUN_RTPG) { -- 1.8.5.6 -- 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
[PATCHv6 15/23] scsi_dh_alua: Add new blacklist flag 'BLIST_SYNC_ALUA'
Add a new blacklist flag BLIST_SYNC_ALUA to instruct the alua device handler to use synchronous command submission for ALUA commands. Reviewed-by: Christoph Hellwig Signed-off-by: Hannes Reinecke --- drivers/scsi/device_handler/scsi_dh_alua.c | 2 ++ drivers/scsi/scsi_devinfo.c| 2 ++ drivers/scsi/scsi_scan.c | 3 +++ include/scsi/scsi_device.h | 1 + include/scsi/scsi_devinfo.h| 1 + 5 files changed, 9 insertions(+) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 43bf6ac..9d5a861 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -366,6 +366,8 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h, /* port group has changed. Update to new port group */ rcu_assign_pointer(h->pg, pg); } + if (sdev->synchronous_alua) + pg->flags |= ALUA_SYNC_STPG; alua_rtpg_queue(h->pg, sdev, NULL); spin_unlock(&h->pg_lock); diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index 47b9d13..b4ef0c6 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -218,6 +218,8 @@ static struct { {"NAKAMICH", "MJ-5.16S", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, {"NEC", "PD-1 ODX654P", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, {"NEC", "iStorage", NULL, BLIST_REPORTLUN2}, + {"NETAPP", "LUN C-Mode", NULL, BLIST_SYNC_ALUA}, + {"NETAPP", "INF-01-00", NULL, BLIST_SYNC_ALUA}, {"NRC", "MBR-7", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, {"NRC", "MBR-7.4", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, {"PIONEER", "CD-ROM DRM-600", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 1f02e84..420239c 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -964,6 +964,9 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result, if (*bflags & BLIST_NO_DIF) sdev->no_dif = 1; + if (*bflags & BLIST_SYNC_ALUA) + sdev->synchronous_alua = 1; + sdev->eh_timeout = SCSI_DEFAULT_EH_TIMEOUT; if (*bflags & BLIST_TRY_VPD_PAGES) diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 9173ab5a..4af2b24 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -176,6 +176,7 @@ struct scsi_device { unsigned no_dif:1; /* T10 PI (DIF) should be disabled */ unsigned broken_fua:1; /* Don't set FUA bit */ unsigned lun_in_cdb:1; /* Store LUN bits in CDB[1] */ + unsigned synchronous_alua:1;/* Synchronous ALUA commands */ atomic_t disk_events_disable_depth; /* disable depth for disk events */ diff --git a/include/scsi/scsi_devinfo.h b/include/scsi/scsi_devinfo.h index 96e3f56..9f750cb 100644 --- a/include/scsi/scsi_devinfo.h +++ b/include/scsi/scsi_devinfo.h @@ -37,5 +37,6 @@ #define BLIST_TRY_VPD_PAGES0x1000 /* Attempt to read VPD pages */ #define BLIST_NO_RSOC 0x2000 /* don't try to issue RSOC */ #define BLIST_MAX_1024 0x4000 /* maximum 1024 sector cdb length */ +#define BLIST_SYNC_ALUA0x8000 /* Synchronous ALUA commands */ #endif -- 1.8.5.6 -- 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
[PATCHv6 16/23] scsi_dh_alua: Recheck state on unit attention
When we receive a unit attention code of 'ALUA state changed' we should recheck the state, as it might be due to an implicit ALUA state transition. This allows us to return NEEDS_RETRY instead of ADD_TO_MLQUEUE, allowing to terminate the retries after a certain time. At the same time a workqueue item might already be queued, which should be started immediately to avoid any delays. Reviewed-by: Christoph Hellwig Signed-off-by: Hannes Reinecke --- drivers/scsi/device_handler/scsi_dh_alua.c | 76 +- 1 file changed, 64 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 9d5a861..08c434a 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -120,7 +120,8 @@ struct alua_queue_data { static void alua_rtpg_work(struct work_struct *work); static void alua_rtpg_queue(struct alua_port_group *pg, struct scsi_device *sdev, - struct alua_queue_data *qdata); + struct alua_queue_data *qdata, bool force); +static void alua_check(struct scsi_device *sdev, bool force); static void release_port_group(struct kref *kref) { @@ -368,7 +369,7 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h, } if (sdev->synchronous_alua) pg->flags |= ALUA_SYNC_STPG; - alua_rtpg_queue(h->pg, sdev, NULL); + alua_rtpg_queue(h->pg, sdev, NULL, true); spin_unlock(&h->pg_lock); if (old_pg) @@ -404,18 +405,24 @@ static int alua_check_sense(struct scsi_device *sdev, { switch (sense_hdr->sense_key) { case NOT_READY: - if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0a) + if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0a) { /* * LUN Not Accessible - ALUA state transition */ - return ADD_TO_MLQUEUE; + alua_check(sdev, false); + return NEEDS_RETRY; + } break; case UNIT_ATTENTION: - if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00) + if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00) { /* -* Power On, Reset, or Bus Device Reset, just retry. +* Power On, Reset, or Bus Device Reset. +* Might have obscured a state transition, +* so schedule a recheck. */ + alua_check(sdev, true); return ADD_TO_MLQUEUE; + } if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x04) /* * Device internal reset @@ -426,16 +433,20 @@ static int alua_check_sense(struct scsi_device *sdev, * Mode Parameters Changed */ return ADD_TO_MLQUEUE; - if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x06) + if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x06) { /* * ALUA state changed */ + alua_check(sdev, true); return ADD_TO_MLQUEUE; - if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x07) + } + if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x07) { /* * Implicit ALUA state transition failed */ + alua_check(sdev, true); return ADD_TO_MLQUEUE; + } if (sense_hdr->asc == 0x3f && sense_hdr->ascq == 0x03) /* * Inquiry data has changed @@ -710,7 +721,7 @@ static void alua_rtpg_work(struct work_struct *work) spin_unlock_irqrestore(&pg->lock, flags); err = alua_rtpg(sdev, pg); spin_lock_irqsave(&pg->lock, flags); - if (err == SCSI_DH_RETRY) { + if (err == SCSI_DH_RETRY || pg->flags & ALUA_PG_RUN_RTPG) { pg->flags &= ~ALUA_PG_RUNNING; pg->flags |= ALUA_PG_RUN_RTPG; spin_unlock_irqrestore(&pg->lock, flags); @@ -726,7 +737,7 @@ static void alua_rtpg_work(struct work_struct *work) spin_unlock_irqrestore(&pg->lock, flags); err = alua_stpg(sdev, pg); spin_lock_irqsave(&pg->lock, flags); - if (err == SCSI_DH_RETRY) { + if (err == SCSI_DH_RETRY || pg->flags & ALUA_PG_RUN_RTPG) { pg->flags |= ALUA_PG_RUN_RTPG; pg->inte
[PATCHv6 11/23] scsi_dh_alua: move optimize_stpg evaluation
When the optimize_stpg module option is set we should just set it once during port_group allocation. Doing so allows us to override it later with device specific settings. Reviewed-by: Christoph Hellwig Signed-off-by: Hannes Reinecke --- drivers/scsi/device_handler/scsi_dh_alua.c | 13 ++--- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 61c67e6..0212aee 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -64,6 +64,10 @@ #define ALUA_OPTIMIZE_STPG 1 #define ALUA_RTPG_EXT_HDR_UNSUPP 2 +static uint optimize_stpg; +module_param(optimize_stpg, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(optimize_stpg, "Allow use of a non-optimized path, rather than sending a STPG, when implicit TPGS is supported (0=No,1=Yes). Default is 0."); + static LIST_HEAD(port_group_list); static DEFINE_SPINLOCK(port_group_lock); @@ -219,6 +223,8 @@ struct alua_port_group *alua_alloc_pg(struct scsi_device *sdev, pg->group_id = group_id; pg->tpgs = tpgs; pg->state = TPGS_STATE_OPTIMIZED; + if (optimize_stpg) + pg->flags |= ALUA_OPTIMIZE_STPG; kref_init(&pg->kref); spin_lock(&port_group_lock); @@ -680,10 +686,6 @@ static int alua_set_params(struct scsi_device *sdev, const char *params) return result; } -static uint optimize_stpg; -module_param(optimize_stpg, uint, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(optimize_stpg, "Allow use of a non-optimized path, rather than sending a STPG, when implicit TPGS is supported (0=No,1=Yes). Default is 0."); - /* * alua_activate - activate a path * @sdev: device on the path to be activated @@ -705,9 +707,6 @@ static int alua_activate(struct scsi_device *sdev, kref_get(&h->pg->kref); - if (optimize_stpg) - h->pg->flags |= ALUA_OPTIMIZE_STPG; - err = alua_rtpg(sdev, h->pg); if (err != SCSI_DH_OK) { kref_put(&h->pg->kref, release_port_group); -- 1.8.5.6 -- 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
[PATCHv6 02/23] scsi_dh_alua: separate out alua_stpg()
Separate out SET TARGET PORT GROUP functionality into a separate function alua_stpg(). Reviewed-by: Christoph Hellwig Signed-off-by: Hannes Reinecke --- drivers/scsi/device_handler/scsi_dh_alua.c | 95 +++--- 1 file changed, 61 insertions(+), 34 deletions(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index df71e85..136bc76 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -579,6 +579,65 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_ } /* + * alua_stpg - Issue a SET TARGET PORT GROUP command + * + * Issue a SET TARGET PORT GROUP command and evaluate the + * response. Returns SCSI_DH_RETRY if the target port group + * state is found to be in 'transitioning'. + * If SCSI_DH_OK is returned the passed-in 'fn' function + * this function will take care of executing 'fn'. + * Otherwise 'fn' should be executed by the caller with the + * returned error code. + */ +static unsigned alua_stpg(struct scsi_device *sdev, struct alua_dh_data *h, + activate_complete fn, void *data) +{ + int err = SCSI_DH_OK; + int stpg = 0; + + if (!(h->tpgs & TPGS_MODE_EXPLICIT)) + /* Only implicit ALUA supported */ + goto out; + + switch (h->state) { + case TPGS_STATE_NONOPTIMIZED: + stpg = 1; + if ((h->flags & ALUA_OPTIMIZE_STPG) && + !h->pref && + (h->tpgs & TPGS_MODE_IMPLICIT)) + stpg = 0; + break; + case TPGS_STATE_STANDBY: + case TPGS_STATE_UNAVAILABLE: + stpg = 1; + break; + case TPGS_STATE_OFFLINE: + err = SCSI_DH_IO; + break; + case TPGS_STATE_TRANSITIONING: + err = SCSI_DH_RETRY; + break; + default: + break; + } + + if (stpg) { + h->callback_fn = fn; + h->callback_data = data; + err = submit_stpg(h); + if (err != SCSI_DH_OK) + h->callback_fn = h->callback_data = NULL; + else + fn = NULL; + } +out: + if (fn) + fn(data, err); + + return err; +} + +/* * alua_initialize - Initialize ALUA state * @sdev: the device to be initialized * @@ -655,7 +714,6 @@ static int alua_activate(struct scsi_device *sdev, { struct alua_dh_data *h = sdev->handler_data; int err = SCSI_DH_OK; - int stpg = 0; err = alua_rtpg(sdev, h, 1); if (err != SCSI_DH_OK) @@ -664,41 +722,10 @@ static int alua_activate(struct scsi_device *sdev, if (optimize_stpg) h->flags |= ALUA_OPTIMIZE_STPG; - if (h->tpgs & TPGS_MODE_EXPLICIT) { - switch (h->state) { - case TPGS_STATE_NONOPTIMIZED: - stpg = 1; - if ((h->flags & ALUA_OPTIMIZE_STPG) && - (!h->pref) && - (h->tpgs & TPGS_MODE_IMPLICIT)) - stpg = 0; - break; - case TPGS_STATE_STANDBY: - case TPGS_STATE_UNAVAILABLE: - stpg = 1; - break; - case TPGS_STATE_OFFLINE: - err = SCSI_DH_IO; - break; - case TPGS_STATE_TRANSITIONING: - err = SCSI_DH_RETRY; - break; - default: - break; - } - } - - if (stpg) { - h->callback_fn = fn; - h->callback_data = data; - err = submit_stpg(h); - if (err == SCSI_DH_OK) - return 0; - h->callback_fn = h->callback_data = NULL; - } + err = alua_stpg(sdev, h, fn, data); out: - if (fn) + if (err != SCSI_DH_OK && fn) fn(data, err); return 0; } -- 1.8.5.6 -- 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
[PATCHv6 09/23] scsi_dh_alua: simplify alua_initialize()
Rework alua_check_vpd() to use scsi_vpd_get_tpg() and move the port group selection into the function, too. With that we can simplify alua_initialize() to just call alua_check_tpgs() and alua_check_vpd(); Reviewed-by: Christoph Hellwig Signed-off-by: Hannes Reinecke --- drivers/scsi/device_handler/scsi_dh_alua.c | 38 +- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 0262085..a1bcad3 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -92,6 +92,7 @@ struct alua_dh_data { #define ALUA_POLICY_SWITCH_CURRENT 0 #define ALUA_POLICY_SWITCH_ALL 1 +static int alua_rtpg(struct scsi_device *, struct alua_port_group *, int); static char print_alua_state(int); static void release_port_group(struct kref *kref) @@ -294,7 +295,8 @@ static int alua_check_tpgs(struct scsi_device *sdev) * Extract the relative target port and the target port group * descriptor from the list of identificators. */ -static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h) +static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h, + int tpgs) { int rel_port = -1, group_id; @@ -310,13 +312,21 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h) ALUA_DH_NAME); return SCSI_DH_DEV_UNSUPP; } - h->group_id = group_id; + + h->pg = alua_alloc_pg(sdev, group_id, tpgs); + if (IS_ERR(h->pg)) { + if (PTR_ERR(h->pg) == -ENOMEM) + return SCSI_DH_NOMEM; + return SCSI_DH_DEV_UNSUPP; + } + h->rel_port = rel_port; sdev_printk(KERN_INFO, sdev, - "%s: port group %x rel port %x\n", - ALUA_DH_NAME, h->group_id, h->rel_port); + "%s: device %s port group %x rel port %x\n", + ALUA_DH_NAME, h->pg->device_id_str, + h->group_id, h->rel_port); - return 0; + return alua_rtpg(sdev, h->pg, 0); } static char print_alua_state(int state) @@ -635,23 +645,9 @@ static int alua_initialize(struct scsi_device *sdev, struct alua_dh_data *h) int err = SCSI_DH_DEV_UNSUPP, tpgs; tpgs = alua_check_tpgs(sdev); - if (tpgs == TPGS_MODE_NONE) - goto out; - - err = alua_check_vpd(sdev, h); - if (err != SCSI_DH_OK) - goto out; + if (tpgs != TPGS_MODE_NONE) + err = alua_check_vpd(sdev, h, tpgs); - h->pg = alua_alloc_pg(sdev, h->group_id, tpgs); - if (IS_ERR(h->pg)) { - if (PTR_ERR(h->pg) == -ENOMEM) - err = SCSI_DH_NOMEM; - goto out; - } - kref_get(&h->pg->kref); - err = alua_rtpg(sdev, h->pg, 0); - kref_put(&h->pg->kref, release_port_group); -out: return err; } /* -- 1.8.5.6 -- 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
[PATCHv6 05/23] scsi_dh_alua: switch to scsi_execute_req_flags()
All commands are issued synchronously, so no need to open-code scsi_execute_req_flags() anymore. And we can get rid of the static sense code structure element. scsi_execute_req_flags() will be setting REQ_QUIET and REQ_PREEMPT, but that is perfectly fine as we're evaluating and logging any errors ourselves and we really need to send the command even if the device is quiesced. Reviewed-by: Christoph Hellwig Reviewed-by: Ewan Milne Signed-off-by: Hannes Reinecke --- drivers/scsi/device_handler/scsi_dh_alua.c | 125 + 1 file changed, 36 insertions(+), 89 deletions(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 77e23a4..2101518 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -75,7 +75,6 @@ struct alua_dh_data { unsigned char *buff; int bufflen; unsigned char transition_tmo; - unsigned char sense[SCSI_SENSE_BUFFERSIZE]; struct scsi_device *sdev; activate_complete callback_fn; void*callback_data; @@ -101,71 +100,30 @@ static int realloc_buffer(struct alua_dh_data *h, unsigned len) return 0; } -static struct request *get_alua_req(struct scsi_device *sdev, - void *buffer, unsigned buflen, int rw) -{ - struct request *rq; - struct request_queue *q = sdev->request_queue; - - rq = blk_get_request(q, rw, GFP_NOIO); - - if (IS_ERR(rq)) { - sdev_printk(KERN_INFO, sdev, - "%s: blk_get_request failed\n", __func__); - return NULL; - } - blk_rq_set_block_pc(rq); - - if (buflen && blk_rq_map_kern(q, rq, buffer, buflen, GFP_NOIO)) { - blk_put_request(rq); - sdev_printk(KERN_INFO, sdev, - "%s: blk_rq_map_kern failed\n", __func__); - return NULL; - } - - rq->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | -REQ_FAILFAST_DRIVER; - rq->retries = ALUA_FAILOVER_RETRIES; - rq->timeout = ALUA_FAILOVER_TIMEOUT * HZ; - - return rq; -} - /* * submit_rtpg - Issue a REPORT TARGET GROUP STATES command * @sdev: sdev the command should be sent to */ -static unsigned submit_rtpg(struct scsi_device *sdev, unsigned char *buff, - int bufflen, unsigned char *sense, int flags) +static int submit_rtpg(struct scsi_device *sdev, unsigned char *buff, + int bufflen, struct scsi_sense_hdr *sshdr, int flags) { - struct request *rq; - int err = 0; - - rq = get_alua_req(sdev, buff, bufflen, READ); - if (!rq) { - err = DRIVER_BUSY << 24; - goto done; - } + u8 cdb[COMMAND_SIZE(MAINTENANCE_IN)]; + int req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | + REQ_FAILFAST_DRIVER; /* Prepare the command. */ - rq->cmd[0] = MAINTENANCE_IN; + memset(cdb, 0x0, COMMAND_SIZE(MAINTENANCE_IN)); + cdb[0] = MAINTENANCE_IN; if (!(flags & ALUA_RTPG_EXT_HDR_UNSUPP)) - rq->cmd[1] = MI_REPORT_TARGET_PGS | MI_EXT_HDR_PARAM_FMT; + cdb[1] = MI_REPORT_TARGET_PGS | MI_EXT_HDR_PARAM_FMT; else - rq->cmd[1] = MI_REPORT_TARGET_PGS; - put_unaligned_be32(bufflen, &rq->cmd[6]); - rq->cmd_len = COMMAND_SIZE(MAINTENANCE_IN); - - rq->sense = sense; - memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); - rq->sense_len = 0; - - blk_execute_rq(rq->q, NULL, rq, 1); - if (rq->errors) - err = rq->errors; - blk_put_request(rq); -done: - return err; + cdb[1] = MI_REPORT_TARGET_PGS; + put_unaligned_be32(bufflen, &cdb[6]); + + return scsi_execute_req_flags(sdev, cdb, DMA_FROM_DEVICE, + buff, bufflen, sshdr, + ALUA_FAILOVER_TIMEOUT * HZ, + ALUA_FAILOVER_RETRIES, NULL, req_flags); } /* @@ -175,40 +133,30 @@ done: * to 'active/optimized' and let the array firmware figure out * the states of the remaining groups. */ -static unsigned submit_stpg(struct scsi_device *sdev, int group_id, - unsigned char *sense) +static int submit_stpg(struct scsi_device *sdev, int group_id, + struct scsi_sense_hdr *sshdr) { - struct request *rq; + u8 cdb[COMMAND_SIZE(MAINTENANCE_OUT)]; unsigned char stpg_data[8]; int stpg_len = 8; - int err = 0; + int req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | + REQ_FAILFAST_DRIVER; /* Prepare the data buffer */ memset(stpg_data, 0, stpg_len); stpg_data[4] = TPGS_STATE_OPTIMIZE
[PATCHv6 00/23] ALUA device handler update, part II
as promised here is now the second part of my ALUA device handler update. This contains a major rework of the ALUA device handler as execution is moved onto a workqueue. This has the advantage that we avoid having to do multiple calls to the same LUN (as happens frequently when failing over a LUN with several paths) and finally retries are handled correctly. As some arrays are only capable of handling one STPG at a time I've added a blacklist flag which then uses a singlethreaded workqueue, thereby effectively synchronize STPG handling. Thanks to Bart for this suggestion. As usual, comments and reviews are welcome. Changes to v5: - Fixup lock imbalance noticed by Bart - use #define instead of enum for access_state as suggested by Ewan - Updated patch description as suggested by Ewan - Changed occurrences to 'SET TARGET PORT GROUP' as suggested by Bart Changes to v4: - use kfree_rcu() as suggested by hch - Use 'IS_ERR' instead of 'PTR_ERR' when checking for validity of a pointer - Simplify pg assignment as suggested by hch - Use separate WARN_ON statements a suggested by hch - Fixes to avoid I/O stall on failover Changes to v3: - Use scsi_device flag for blacklisting as suggested by hch - Add Arrays for synchronous ALUA handling - Move synchronize_rcu() into release_port_group() - Add remaining reviewed tags Changes to v2: - Use a SCSI blacklist flag instead of a hardware handler parameter for switching to synchronous ALUA handling - Move scsi_get_device_flags{,_keyed} to scsi_devinfo.h - Move flush_delayed_work() into release_port_group() - Rename alua_lookup_pg() into alua_find_get_pg() - Add __rcu annotations to keep sparse happy Changes to v1: - Include reviews from hch - Switch to hardware handler parameter instead of module option Hannes Reinecke (23): scsi_dh_alua: Pass buffer as function argument scsi_dh_alua: separate out alua_stpg() scsi_dh_alua: Make stpg synchronous scsi_dh_alua: call alua_rtpg() if stpg fails scsi_dh_alua: switch to scsi_execute_req_flags() scsi_dh_alua: allocate RTPG buffer separately scsi_dh_alua: Use separate alua_port_group structure scsi_dh_alua: use unique device id scsi_dh_alua: simplify alua_initialize() revert commit a8e5a2d593cb ("[SCSI] scsi_dh_alua: ALUA handler attach should succeed while TPG is transitioning") scsi_dh_alua: move optimize_stpg evaluation scsi_dh_alua: remove 'rel_port' from alua_dh_data structure scsi_dh_alua: Use workqueue for RTPG scsi_dh_alua: Allow workqueue to run synchronously scsi_dh_alua: Add new blacklist flag 'BLIST_SYNC_ALUA' scsi_dh_alua: Recheck state on unit attention scsi_dh_alua: update all port states scsi_dh_alua: Send TEST UNIT READY to poll for transitioning scsi_dh: add 'rescan' callback scsi: Add 'access_state' attribute scsi_dh_alua: use common definitions for ALUA state scsi_dh_alua: update 'access_state' field scsi_dh_alua: Update version to 2.0 drivers/scsi/device_handler/scsi_dh_alua.c | 990 - drivers/scsi/scsi_devinfo.c| 2 + drivers/scsi/scsi_lib.c| 1 + drivers/scsi/scsi_scan.c | 12 +- drivers/scsi/scsi_sysfs.c | 49 ++ include/scsi/scsi_device.h | 2 + include/scsi/scsi_devinfo.h| 1 + include/scsi/scsi_dh.h | 2 + include/scsi/scsi_proto.h | 12 + 9 files changed, 764 insertions(+), 307 deletions(-) -- 1.8.5.6 -- 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
[PATCHv6 17/23] scsi_dh_alua: update all port states
When we read in the target port group state we should be updating all affected port groups, otherwise we risk running out of sync. Reviewed-by: Christoph Hellwig Signed-off-by: Hannes Reinecke --- drivers/scsi/device_handler/scsi_dh_alua.c | 35 ++ 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 08c434a..ed77b7c 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -476,11 +476,13 @@ static int alua_check_sense(struct scsi_device *sdev, static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg) { struct scsi_sense_hdr sense_hdr; + struct alua_port_group *tmp_pg; int len, k, off, valid_states = 0, bufflen = ALUA_RTPG_SIZE; - unsigned char *ucp, *buff; + unsigned char *desc, *buff; unsigned err, retval; unsigned int tpg_desc_tbl_off; unsigned char orig_transition_tmo; + unsigned long flags; if (!pg->expiry) { unsigned long transition_tmo = ALUA_FAILOVER_TIMEOUT * HZ; @@ -582,18 +584,32 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg) else tpg_desc_tbl_off = 4; - for (k = tpg_desc_tbl_off, ucp = buff + tpg_desc_tbl_off; + for (k = tpg_desc_tbl_off, desc = buff + tpg_desc_tbl_off; k < len; -k += off, ucp += off) { - - if (pg->group_id == get_unaligned_be16(&ucp[2])) { - pg->state = ucp[0] & 0x0f; - pg->pref = ucp[0] >> 7; - valid_states = ucp[1]; +k += off, desc += off) { + u16 group_id = get_unaligned_be16(&desc[2]); + + spin_lock_irqsave(&port_group_lock, flags); + tmp_pg = alua_find_get_pg(pg->device_id_str, pg->device_id_len, + group_id); + spin_unlock_irqrestore(&port_group_lock, flags); + if (tmp_pg) { + if (spin_trylock_irqsave(&tmp_pg->lock, flags)) { + if ((tmp_pg == pg) || + !(tmp_pg->flags & ALUA_PG_RUNNING)) { + tmp_pg->state = desc[0] & 0x0f; + tmp_pg->pref = desc[0] >> 7; + } + if (tmp_pg == pg) + valid_states = desc[1]; + spin_unlock_irqrestore(&tmp_pg->lock, flags); + } + kref_put(&tmp_pg->kref, release_port_group); } - off = 8 + (ucp[7] * 4); + off = 8 + (desc[7] * 4); } + spin_lock_irqsave(&pg->lock, flags); sdev_printk(KERN_INFO, sdev, "%s: port group %02x state %c %s supports %c%c%c%c%c%c%c\n", ALUA_DH_NAME, pg->group_id, print_alua_state(pg->state), @@ -630,6 +646,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg) pg->expiry = 0; break; } + spin_unlock_irqrestore(&pg->lock, flags); kfree(buff); return err; } -- 1.8.5.6 -- 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
[PATCHv6 03/23] scsi_dh_alua: Make stpg synchronous
The 'activate_complete' function needs to be executed after stpg has finished, so we can as well execute stpg synchronously and call the function directly. Reviewed-by: Christoph Hellwig Signed-off-by: Hannes Reinecke --- drivers/scsi/device_handler/scsi_dh_alua.c | 156 ++--- 1 file changed, 54 insertions(+), 102 deletions(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 136bc76..ceca554 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -169,81 +169,28 @@ done: } /* - * stpg_endio - Evaluate SET TARGET GROUP STATES - * @sdev: the device to be evaluated - * @state: the new target group state - * - * Evaluate a SET TARGET GROUP STATES command response. - */ -static void stpg_endio(struct request *req, int error) -{ - struct alua_dh_data *h = req->end_io_data; - struct scsi_sense_hdr sense_hdr; - unsigned err = SCSI_DH_OK; - - if (host_byte(req->errors) != DID_OK || - msg_byte(req->errors) != COMMAND_COMPLETE) { - err = SCSI_DH_IO; - goto done; - } - - if (scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE, -&sense_hdr)) { - if (sense_hdr.sense_key == NOT_READY && - sense_hdr.asc == 0x04 && sense_hdr.ascq == 0x0a) { - /* ALUA state transition already in progress */ - err = SCSI_DH_OK; - goto done; - } - if (sense_hdr.sense_key == UNIT_ATTENTION) { - err = SCSI_DH_RETRY; - goto done; - } - sdev_printk(KERN_INFO, h->sdev, "%s: stpg failed\n", - ALUA_DH_NAME); - scsi_print_sense_hdr(h->sdev, ALUA_DH_NAME, &sense_hdr); - err = SCSI_DH_IO; - } else if (error) - err = SCSI_DH_IO; - - if (err == SCSI_DH_OK) { - h->state = TPGS_STATE_OPTIMIZED; - sdev_printk(KERN_INFO, h->sdev, - "%s: port group %02x switched to state %c\n", - ALUA_DH_NAME, h->group_id, - print_alua_state(h->state)); - } -done: - req->end_io_data = NULL; - __blk_put_request(req->q, req); - if (h->callback_fn) { - h->callback_fn(h->callback_data, err); - h->callback_fn = h->callback_data = NULL; - } - return; -} - -/* - * submit_stpg - Issue a SET TARGET GROUP STATES command + * submit_stpg - Issue a SET TARGET PORT GROUP command * * Currently we're only setting the current target port group state * to 'active/optimized' and let the array firmware figure out * the states of the remaining groups. */ -static unsigned submit_stpg(struct alua_dh_data *h) +static unsigned submit_stpg(struct scsi_device *sdev, int group_id, + unsigned char *sense) { struct request *rq; + unsigned char stpg_data[8]; int stpg_len = 8; - struct scsi_device *sdev = h->sdev; + int err = 0; /* Prepare the data buffer */ - memset(h->buff, 0, stpg_len); - h->buff[4] = TPGS_STATE_OPTIMIZED & 0x0f; - put_unaligned_be16(h->group_id, &h->buff[6]); + memset(stpg_data, 0, stpg_len); + stpg_data[4] = TPGS_STATE_OPTIMIZED & 0x0f; + put_unaligned_be16(group_id, &stpg_data[6]); - rq = get_alua_req(sdev, h->buff, stpg_len, WRITE); + rq = get_alua_req(sdev, stpg_data, stpg_len, WRITE); if (!rq) - return SCSI_DH_RES_TEMP_UNAVAIL; + return DRIVER_BUSY << 24; /* Prepare the command. */ rq->cmd[0] = MAINTENANCE_OUT; @@ -251,13 +198,17 @@ static unsigned submit_stpg(struct alua_dh_data *h) put_unaligned_be32(stpg_len, &rq->cmd[6]); rq->cmd_len = COMMAND_SIZE(MAINTENANCE_OUT); - rq->sense = h->sense; + rq->sense = sense; memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); rq->sense_len = 0; - rq->end_io_data = h; - blk_execute_rq_nowait(rq->q, NULL, rq, 1, stpg_endio); - return SCSI_DH_OK; + blk_execute_rq(rq->q, NULL, rq, 1); + if (rq->errors) + err = rq->errors; + + blk_put_request(rq); + + return err; } /* @@ -582,59 +533,61 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_ * alua_stpg - Issue a SET TARGET PORT GROUP command * * Issue a SET TARGET PORT GROUP command and evaluate the - * response. Returns SCSI_DH_RETRY if the target port group - * state is found to be in 'transitioning'. - * If SCSI_DH_OK is returned the passed-in 'fn' function - * this function will take care of executing 'fn'. - * Otherwise 'fn' should be executed by the caller with the - * returned error code.
Re: [PATCH] ibmvfc: byteswap scsi_id, wwpn, and node_name prior to logging
On Thu, Feb 11, 2016 at 04:24:35PM -0600, Tyrel Datwyler wrote: > When logging async events the scsi_id, wwpn, and node_name values > are used directly from the CRQ struct which are of type __be64. This > can be confusing to someone looking through the log on a LE system. > Instead byteswap these values to host endian prior to logging. > > Signed-off-by: Tyrel Datwyler Reviewed-by: Johannes Thumshirn -- Johannes Thumshirn Storage jthumsh...@suse.de+49 911 74053 689 SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg GF: Felix Imendörffer, Jane Smithard, Graham Norton HRB 21284 (AG Nürnberg) Key fingerprint = EC38 9CAB C2C4 F25D 8600 D0D0 0393 969D 2D76 0850 -- 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