Re: [PATCH] esas2r: Fix array overrun

2016-02-15 Thread Johannes Thumshirn
On Mon, Feb 15, 2016 at 07:01:29PM +, Alan wrote:
> Check the array size *before* dereferencing it with a user provided offset
> 
> Signed-off-by: Alan Cox 
> ---
>  drivers/scsi/esas2r/esas2r_ioctl.c |5 +++--
>  1 file changed, 3 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/scsi/esas2r/esas2r_ioctl.c 
> b/drivers/scsi/esas2r/esas2r_ioctl.c
> index baf9130..3e84834 100644
> --- a/drivers/scsi/esas2r/esas2r_ioctl.c
> +++ b/drivers/scsi/esas2r/esas2r_ioctl.c
> @@ -1360,14 +1360,15 @@ int esas2r_ioctl_handler(void *hostdata, int cmd, 
> void __user *arg)
>   if (ioctl->header.channel == 0xFF) {
>   a = (struct esas2r_adapter *)hostdata;
>   } else {
> - a = esas2r_adapters[ioctl->header.channel];
> - if (ioctl->header.channel >= MAX_ADAPTERS || (a == NULL)) {
> + if (ioctl->header.channel >= MAX_ADAPTERS ||
> + esas2r_adapters[ioctl->header.channel] == NULL) {
>   ioctl->header.return_code = IOCTL_BAD_CHANNEL;
>   esas2r_log(ESAS2R_LOG_WARN, "bad channel value");
>   kfree(ioctl);
>  
>   return -ENOTSUPP;
>   }
> + a = esas2r_adapters[ioctl->header.channel];
>   }
>  
>   switch (cmd) {
> 
> --
> 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

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


Re: [PATCH] lpfc: fix missing zero termination in debugfs

2016-02-15 Thread Johannes Thumshirn
On Mon, Feb 15, 2016 at 07:11:56PM +, Alan wrote:
> If you feed 32 bytes in then the kstrtoull() doesn't receive a terminated
> string so will run off the end.
> 
> Signed-off-by: Alan Cox 
> ---
>  drivers/scsi/lpfc/lpfc_debugfs.c |4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c 
> b/drivers/scsi/lpfc/lpfc_debugfs.c
> index 25aa9b9..a63542b 100644
> --- a/drivers/scsi/lpfc/lpfc_debugfs.c
> +++ b/drivers/scsi/lpfc/lpfc_debugfs.c
> @@ -1054,11 +1054,11 @@ lpfc_debugfs_dif_err_write(struct file *file, const 
> char __user *buf,
>  {
>   struct dentry *dent = file->f_path.dentry;
>   struct lpfc_hba *phba = file->private_data;
> - char dstbuf[32];
> + char dstbuf[33];
>   uint64_t tmp = 0;
>   int size;
>  
> - memset(dstbuf, 0, 32);
> + memset(dstbuf, 0, 33);
>   size = (nbytes < 32) ? nbytes : 32;
>   if (copy_from_user(dstbuf, buf, size))
>   return 0;
> 

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


Re: [PATCH] aic7xxx: Fix queue depth handling

2016-02-15 Thread Hannes Reinecke
On 02/15/2016 07:53 PM, Alan wrote:
> We were setting the queue depth correctly, then setting it back to two. If
> you hit this as a bisection point then please send me an email as it would
> imply we've been hiding other bugs with this one.
> 
> Signed-off-by: Alan Cox 
> ---
>  drivers/scsi/aic7xxx/aic7xxx_osm.c |1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c 
> b/drivers/scsi/aic7xxx/aic7xxx_osm.c
> index b846a46..fc6a831 100644
> --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c
> +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c
> @@ -1336,6 +1336,7 @@ ahc_platform_set_tags(struct ahc_softc *ahc, struct 
> scsi_device *sdev,
>   case AHC_DEV_Q_TAGGED:
>   scsi_change_queue_depth(sdev,
>   dev->openings + dev->active);
> + break;
>   default:
>   /*
>* We allow the OS to queue 2 untagged transactions to
> 
> 
Reviewed-by: Hannes Reinecke 

Cheers,

Hannes
-- 
Dr. Hannes ReineckezSeries & Storage
h...@suse.com  +49 911 74053 688
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton
HRB 21284 (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


[PATCH] fusion-mptbase: handle failed allocation for workqueue

2016-02-15 Thread Insu Yun
the failure of ioc->reset_work_q is checked,
but not ioc->fw_event_q.

Signed-off-by: Insu Yun 
---
 drivers/message/fusion/mptbase.c | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index 5dcc031..d4907a1 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -1996,6 +1996,13 @@ mpt_attach(struct pci_dev *pdev, const struct 
pci_device_id *id)
snprintf(ioc->fw_event_q_name, MPT_KOBJ_NAME_LEN, "mpt/%d", ioc->id);
ioc->fw_event_q = create_singlethread_workqueue(ioc->fw_event_q_name);
 
+   if (!ioc->fw_event_q) {
+   destroy_workqueue(ioc->reset_work_q);
+   pci_release_selected_regions(pdev, ioc->bars);
+   kfree(ioc);
+   return -ENOMEM;
+   }
+
if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
CAN_SLEEP)) != 0){
printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Bug 111341] Firmware loader

2016-02-15 Thread bugzilla-daemon
https://bugzilla.kernel.org/show_bug.cgi?id=111341

--- Comment #4 from walter59  ---
sorry --- bug is always on -- only on the one board with c600 intel it works,

five other boards doesnt .  all asus boards x79 / 2011 Intel.

in next days me look for differenz between bios and so on !

regards

-- 
You are receiving this mail because:
You are watching the assignee of the bug.
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Bug 111341] Firmware loader

2016-02-15 Thread bugzilla-daemon
https://bugzilla.kernel.org/show_bug.cgi?id=111341

--- Comment #3 from walter59  ---
fine --- changes in kernel 4.5-rc4  ahci for c600 intel id 1d02 now ok !

thanks to all !

-- 
You are receiving this mail because:
You are watching the assignee of the bug.
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH] lpfc: fix missing zero termination in debugfs

2016-02-15 Thread Alan
If you feed 32 bytes in then the kstrtoull() doesn't receive a terminated
string so will run off the end.

Signed-off-by: Alan Cox 
---
 drivers/scsi/lpfc/lpfc_debugfs.c |4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c
index 25aa9b9..a63542b 100644
--- a/drivers/scsi/lpfc/lpfc_debugfs.c
+++ b/drivers/scsi/lpfc/lpfc_debugfs.c
@@ -1054,11 +1054,11 @@ lpfc_debugfs_dif_err_write(struct file *file, const 
char __user *buf,
 {
struct dentry *dent = file->f_path.dentry;
struct lpfc_hba *phba = file->private_data;
-   char dstbuf[32];
+   char dstbuf[33];
uint64_t tmp = 0;
int size;
 
-   memset(dstbuf, 0, 32);
+   memset(dstbuf, 0, 33);
size = (nbytes < 32) ? nbytes : 32;
if (copy_from_user(dstbuf, buf, size))
return 0;

--
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

2016-02-15 Thread Himanshu Madhani
Hi Nic,



On 2/12/16, 11:03 PM, "Nicholas A. Bellinger"  wrote:

>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 

Re: [PATCH] aic7xxx: Fix queue depth handling

2016-02-15 Thread James Bottomley
On Mon, 2016-02-15 at 18:53 +, Alan wrote:
> We were setting the queue depth correctly, then setting it back to 
> two. If you hit this as a bisection point then please send me an 
> email as it would imply we've been hiding other bugs with this one.
> 
> Signed-off-by: Alan Cox 
> ---
>  drivers/scsi/aic7xxx/aic7xxx_osm.c |1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c
> b/drivers/scsi/aic7xxx/aic7xxx_osm.c
> index b846a46..fc6a831 100644
> --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c
> +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c
> @@ -1336,6 +1336,7 @@ ahc_platform_set_tags(struct ahc_softc *ahc,
> struct scsi_device *sdev,
>   case AHC_DEV_Q_TAGGED:
>   scsi_change_queue_depth(sdev,
>   dev->openings + dev->active);
> + break;
>   default:
>   

Heh, that's a bit of an oopsie.  I'll add a cc to stable to see what
happens with older kernels.

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


[PATCH] esas2r: Fix array overrun

2016-02-15 Thread Alan
Check the array size *before* dereferencing it with a user provided offset

Signed-off-by: Alan Cox 
---
 drivers/scsi/esas2r/esas2r_ioctl.c |5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/esas2r/esas2r_ioctl.c 
b/drivers/scsi/esas2r/esas2r_ioctl.c
index baf9130..3e84834 100644
--- a/drivers/scsi/esas2r/esas2r_ioctl.c
+++ b/drivers/scsi/esas2r/esas2r_ioctl.c
@@ -1360,14 +1360,15 @@ int esas2r_ioctl_handler(void *hostdata, int cmd, void 
__user *arg)
if (ioctl->header.channel == 0xFF) {
a = (struct esas2r_adapter *)hostdata;
} else {
-   a = esas2r_adapters[ioctl->header.channel];
-   if (ioctl->header.channel >= MAX_ADAPTERS || (a == NULL)) {
+   if (ioctl->header.channel >= MAX_ADAPTERS ||
+   esas2r_adapters[ioctl->header.channel] == NULL) {
ioctl->header.return_code = IOCTL_BAD_CHANNEL;
esas2r_log(ESAS2R_LOG_WARN, "bad channel value");
kfree(ioctl);
 
return -ENOTSUPP;
}
+   a = esas2r_adapters[ioctl->header.channel];
}
 
switch (cmd) {

--
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] aic7xxx: Fix queue depth handling

2016-02-15 Thread Alan
We were setting the queue depth correctly, then setting it back to two. If
you hit this as a bisection point then please send me an email as it would
imply we've been hiding other bugs with this one.

Signed-off-by: Alan Cox 
---
 drivers/scsi/aic7xxx/aic7xxx_osm.c |1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c 
b/drivers/scsi/aic7xxx/aic7xxx_osm.c
index b846a46..fc6a831 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c
@@ -1336,6 +1336,7 @@ ahc_platform_set_tags(struct ahc_softc *ahc, struct 
scsi_device *sdev,
case AHC_DEV_Q_TAGGED:
scsi_change_queue_depth(sdev,
dev->openings + dev->active);
+   break;
default:
/*
 * We allow the OS to queue 2 untagged transactions to

--
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

2016-02-15 Thread Chris Leech
On Fri, Feb 12, 2016 at 09:54:51AM -0800, 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?  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.

I've got a few complaints about target resources being tied up because
we don't reuse session IDs.  The ISID becomes a component in the
I_T nexus identifier, so changing it invalidates persistent reservations.

> If you can demostrate a multi-target problem, perhaps we should rather
> fix this by making the next session id a target local quantity?

Mike's got a good point that we don't really need to base the ISID off
of our local session identifier (kobject name).  I think getting reuse
right may be a bit trickier than being a target local value, because it
needs to be unique across target portal groups.  Which probably furthers
the argument that we should deal with that in the userspace tools.

If we plan to split the protocol ISID cleanly from the kobject name,
I guess the question is if aggressive reuse of the local identifier is
better than dealing with the unlikely collision on rollover?

- Chris
--
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: [RFC 22/34] iscsi-target: call Rx thread function

2016-02-15 Thread Sagi Grimberg



call Rx thread function if registered
by transport driver, so that transport
drivers can use iscsi-target Rx thread
for Rx processing.

update iSER target driver to use this
interface.

Signed-off-by: Varun Prakash 


Other than the handler name, looks harmless.

Acked-by: Sagi Grimberg 
--
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: [RFC 20/34] iscsi-target: update struct iscsit_transport definition

2016-02-15 Thread Sagi Grimberg



1. void (*iscsit_rx_pdu)(struct iscsi_conn *);
Rx thread uses this for receiving and processing
iSCSI PDU in full feature phase.


Is iscsit_rx_pdu the best name for this? it sounds like
a function that would handle A pdu, but it's actually the
thread function dequeuing pdus correct?
--
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: [RFC 19/34] iscsi-target: clear tx_thread_active

2016-02-15 Thread Sagi Grimberg



On 14/02/2016 19:42, Varun Prakash wrote:

clear tx_thread_active for ISCSI_TCP_CXGB4
transport in logout_post_handler functions.

Signed-off-by: Varun Prakash 
---
  drivers/target/iscsi/iscsi_target.c | 6 --
  1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/target/iscsi/iscsi_target.c 
b/drivers/target/iscsi/iscsi_target.c
index 858f6e4..3dd7ba2 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -4579,7 +4579,8 @@ static void iscsit_logout_post_handler_closesession(
 * always sleep waiting for RX/TX thread shutdown to complete
 * within iscsit_close_connection().
 */
-   if (conn->conn_transport->transport_type == ISCSI_TCP)
+   if ((conn->conn_transport->transport_type == ISCSI_TCP) ||
+   (conn->conn_transport->transport_type == ISCSI_TCP_CXGB4))
sleep = cmpxchg(>tx_thread_active, true, false);


Again, this is not the right way to make progress...
--
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: [RFC 18/34] iscsi-target: call complete on conn_logout_comp

2016-02-15 Thread Sagi Grimberg



On 14/02/2016 19:42, Varun Prakash wrote:

ISCSI_TCP_CXGB4 driver waits on conn_logout_comp as
ISCSI_TCP driver so call complete if transport type
is ISCSI_TCP_CXGB4.

Signed-off-by: Varun Prakash 
---
  drivers/target/iscsi/iscsi_target.c | 10 ++
  1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/target/iscsi/iscsi_target.c 
b/drivers/target/iscsi/iscsi_target.c
index 8bf3cfb..858f6e4 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -4265,16 +4265,18 @@ int iscsit_close_connection(
pr_debug("Closing iSCSI connection CID %hu on SID:"
" %u\n", conn->cid, sess->sid);
/*
-* Always up conn_logout_comp for the traditional TCP case just in case
-* the RX Thread in iscsi_target_rx_opcode() is sleeping and the logout
-* response never got sent because the connection failed.
+* Always up conn_logout_comp for the traditional TCP and TCP_CXGB4
+* case just in case the RX Thread in iscsi_target_rx_opcode() is
+* sleeping and the logout response never got sent because the
+* connection failed.
 *
 * However for iser-target, isert_wait4logout() is using 
conn_logout_comp
 * to signal logout response TX interrupt completion.  Go ahead and skip
 * this for iser since isert_rx_opcode() does not wait on logout 
failure,
 * and to avoid iscsi_conn pointer dereference in iser-target code.
 */
-   if (conn->conn_transport->transport_type == ISCSI_TCP)
+   if ((conn->conn_transport->transport_type == ISCSI_TCP) ||
+   (conn->conn_transport->transport_type == ISCSI_TCP_CXGB4))
complete(>conn_logout_comp);


IMO, this is an indication that this condition is a bandage in the first
place...

While this is unrelated to the patch set, we should look into the iscsi
termination sequences more closely and look if we can dispatch some
logic to the drivers in places they defer. It will make the code much
less complicated.
--
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 v8 2/3] added UFS 2.0 capabilities

2016-02-15 Thread Joao Pinto
Adding UFS 2.0 support to the UFS core driver.

Signed-off-by: Joao Pinto 
---
Changes v7->v8:
- Added "jedec, ufs-2.0" to the ufschd-platform compatibility strings
Changes v0->v7:
- Nothing changed (just to keep up with patch set version).

 .../devicetree/bindings/ufs/ufshcd-pltfrm.txt  |  4 +--
 drivers/scsi/ufs/ufshcd.c  | 29 +++---
 drivers/scsi/ufs/ufshci.h  |  1 +
 3 files changed, 28 insertions(+), 6 deletions(-)

diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt 
b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
index 03c0e98..8d9a9d2 100644
--- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
+++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
@@ -4,8 +4,8 @@ UFSHC nodes are defined to describe on-chip UFS host 
controllers.
 Each UFS controller instance should have its own node.
 
 Required properties:
-- compatible   : must contain "jedec,ufs-1.1", may also list one or 
more
- of the following:
+- compatible   : must contain "jedec,ufs-1.1" or "jedec,ufs-2.0", may
+ also list one or more of the following:
  "qcom,msm8994-ufshc"
  "qcom,msm8996-ufshc"
  "qcom,ufshc"
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 85cd256..2b5f2bf 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -1223,6 +1223,7 @@ static int ufshcd_compose_upiu(struct ufs_hba *hba, 
struct ufshcd_lrb *lrbp)
ret = -EINVAL;
}
break;
+   case UTP_CMD_TYPE_UFS_STORAGE:
case UTP_CMD_TYPE_DEV_MANAGE:
ufshcd_prepare_req_desc_hdr(lrbp, _flags, DMA_NONE);
if (hba->dev_cmd.type == DEV_CMD_TYPE_QUERY)
@@ -1287,6 +1288,7 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, 
struct scsi_cmnd *cmd)
struct ufshcd_lrb *lrbp;
struct ufs_hba *hba;
unsigned long flags;
+   u32 upiu_flags;
int tag;
int err = 0;
 
@@ -1343,10 +1345,23 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, 
struct scsi_cmnd *cmd)
lrbp->task_tag = tag;
lrbp->lun = ufshcd_scsi_to_upiu_lun(cmd->device->lun);
lrbp->intr_cmd = !ufshcd_is_intr_aggr_allowed(hba) ? true : false;
-   lrbp->command_type = UTP_CMD_TYPE_SCSI;
+
+   if (hba->ufs_version == UFSHCI_VERSION_20)
+   lrbp->command_type = UTP_CMD_TYPE_UFS_STORAGE;
+   else
+   lrbp->command_type = UTP_CMD_TYPE_SCSI;
 
/* form UPIU before issuing the command */
-   ufshcd_compose_upiu(hba, lrbp);
+   if (hba->ufs_version == UFSHCI_VERSION_20) {
+   if (likely(lrbp->cmd)) {
+   ufshcd_prepare_req_desc_hdr(lrbp, _flags,
+   lrbp->cmd->sc_data_direction);
+   ufshcd_prepare_utp_scsi_cmd_upiu(lrbp, upiu_flags);
+   } else
+   err = -EINVAL;
+   } else
+   ufshcd_compose_upiu(hba, lrbp);
+
err = ufshcd_map_sg(lrbp);
if (err) {
lrbp->cmd = NULL;
@@ -1371,7 +1386,12 @@ static int ufshcd_compose_dev_cmd(struct ufs_hba *hba,
lrbp->sense_buffer = NULL;
lrbp->task_tag = tag;
lrbp->lun = 0; /* device management cmd is not specific to any LUN */
-   lrbp->command_type = UTP_CMD_TYPE_DEV_MANAGE;
+
+   if (hba->ufs_version == UFSHCI_VERSION_20)
+   lrbp->command_type = UTP_CMD_TYPE_UFS_STORAGE;
+   else
+   lrbp->command_type = UTP_CMD_TYPE_DEV_MANAGE;
+
lrbp->intr_cmd = true; /* No interrupt aggregation */
hba->dev_cmd.type = cmd_type;
 
@@ -3187,7 +3207,8 @@ static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
/* Do not touch lrbp after scsi done */
cmd->scsi_done(cmd);
__ufshcd_release(hba);
-   } else if (lrbp->command_type == UTP_CMD_TYPE_DEV_MANAGE) {
+   } else if (lrbp->command_type == UTP_CMD_TYPE_DEV_MANAGE ||
+   lrbp->command_type == UTP_CMD_TYPE_UFS_STORAGE) {
if (hba->dev_cmd.complete)
complete(hba->dev_cmd.complete);
}
diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
index 0ae0967..8dba0e7 100644
--- a/drivers/scsi/ufs/ufshci.h
+++ b/drivers/scsi/ufs/ufshci.h
@@ -273,6 +273,7 @@ enum {
UTP_CMD_TYPE_SCSI   = 0x0,
UTP_CMD_TYPE_UFS= 0x1,
UTP_CMD_TYPE_DEV_MANAGE = 0x2,
+   UTP_CMD_TYPE_UFS_STORAGE= 0x11,
 };
 
 enum {
-- 
1.8.1.5

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in

[PATCH v8 1/3] fixed typo in ufshcd-pltfrm

2016-02-15 Thread Joao Pinto
Fixed typo in ufshcd-pltfrm.

Signed-off-by: Joao Pinto 
---
Changes v0->v8:
- Nothing changed (just to keep up with patch set version).

 drivers/scsi/ufs/ufshcd-pltfrm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index d2a7b12..0522891 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -353,6 +353,6 @@ EXPORT_SYMBOL_GPL(ufshcd_pltfrm_init);
 
 MODULE_AUTHOR("Santosh Yaragnavi ");
 MODULE_AUTHOR("Vinayak Holikatti ");
-MODULE_DESCRIPTION("UFS host controller Pltform bus based glue driver");
+MODULE_DESCRIPTION("UFS host controller Platform bus based glue driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(UFSHCD_DRIVER_VERSION);
-- 
1.8.1.5

--
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 v8 3/3] add support for DWC UFS Host Controller

2016-02-15 Thread Joao Pinto
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 v7->v8 (Akinobu Mita):
- DME sets were simplified for easier reading
- CLK DIV default values definitions names were changed to match the
 register's name
- New line added to dev_err and dev_info statements
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 |  19 +
 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|  96 +
 drivers/scsi/ufs/ufshcd-dwc.c | 431 ++
 drivers/scsi/ufs/ufshcd-dwc.h |  18 +
 drivers/scsi/ufs/ufshci-dwc.h |  42 +++
 drivers/scsi/ufs/unipro.h |  39 ++
 10 files changed, 877 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..59e9822
--- /dev/null
+++ b/Documentation/devicetree/bindings/ufs/ufs-dwc.txt
@@ -0,0 +1,19 @@
+* 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 list must contain "snps,ufshcd-dwc" and should
+ also contain the JEDEC version of the controller:
+   "jedec,ufs-1.1"
+   "jedec,ufs-2.0"
+- reg   : 
+- interrupts: 
+
+Example:
+   ufs@0xd000 {
+   compatible = "jedec,ufs-2.0", "snps,dwc-ufshcd";
+   reg = < 0xd000 0x1 >;
+   interrupts = < 24 >;
+   };
diff --git a/MAINTAINERS b/MAINTAINERS
index d2f94e2..3db3c4c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -11006,6 +11006,12 @@ S: Supported
 F: Documentation/scsi/ufs.txt
 F: drivers/scsi/ufs/
 
+UNIVERSAL FLASH STORAGE HOST CONTROLLER DRIVER DWC HOOKS
+M: Joao Pinto 
+L: linux-scsi@vger.kernel.org
+S: Supported
+F: drivers/scsi/ufs/*dwc*
+
 UNSORTED BLOCK IMAGES (UBI)
 M: Artem Bityutskiy 
 M: Richard Weinberger 
diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig
index 5f45307..35e9ddf 100644
--- a/drivers/scsi/ufs/Kconfig
+++ b/drivers/scsi/ufs/Kconfig
@@ -83,3 +83,54 @@ config SCSI_UFS_QCOM
 
  Select this if you have UFS controller on QCOM chipset.
  If unsure, say N.
+
+config SCSI_UFS_DWC_HOOKS
+   bool
+
+config SCSI_UFS_DWC_PLAT
+   

[PATCH v8 0/3] add support for DWC UFS Controller

2016-02-15 Thread Joao Pinto
The work consisted of:
- Fixed typo in ufshcd-pltfrm.c
- Tweak ufshcd.c for UFS 2.0 support
- Implement ufshcd-dwc which contains all DWC HW specific code
- Unipro attributes were added and new registers were added to the driver
- Implement a ufs-dwc glue platform driver
- Implement a ufs-dwc-pci glue pci driver
- Documentation update

Joao Pinto (3):
  fixed typo in ufshcd-pltfrm
  added UFS 2.0 capabilities
  add support for DWC UFS Host Controller

 Documentation/devicetree/bindings/ufs/ufs-dwc.txt  |  19 +
 .../devicetree/bindings/ufs/ufshcd-pltfrm.txt  |   4 +-
 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 |  96 +
 drivers/scsi/ufs/ufshcd-dwc.c  | 431 +
 drivers/scsi/ufs/ufshcd-dwc.h  |  18 +
 drivers/scsi/ufs/ufshcd-pltfrm.c   |   2 +-
 drivers/scsi/ufs/ufshcd.c  |  29 +-
 drivers/scsi/ufs/ufshci-dwc.h  |  42 ++
 drivers/scsi/ufs/ufshci.h  |   1 +
 drivers/scsi/ufs/unipro.h  |  39 ++
 14 files changed, 906 insertions(+), 7 deletions(-)
 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

-- 
1.8.1.5

--
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

2016-02-15 Thread Joao Pinto
Hi Akinobu,

On 2/13/2016 1:27 PM, Akinobu Mita wrote:
> Hi Joao,
> 
> 2016-02-11 21:13 GMT+09:00 Joao Pinto :
>> +static int ufshcd_dwc_connection_setup(struct ufs_hba *hba)
>> +{
>> +   int ret = 0;
>> +
>> +   /* Local side Configuration */
>> +   ret = ufshcd_dme_set(hba, UIC_ARG_MIB(T_CONNECTIONSTATE), 0);
>> +   if (ret)
>> +   goto out;
>> +
>> +   ret = ufshcd_dme_set(hba, UIC_ARG_MIB(N_DEVICEID), 0);
>> +   if (ret)
>> +   goto out;
>> +
>> +   ret = ufshcd_dme_set(hba, UIC_ARG_MIB(N_DEVICEID_VALID), 0);
>> +   if (ret)
>> +   goto out;
>> +
>> +   ret = ufshcd_dme_set(hba, UIC_ARG_MIB(T_PEERDEVICEID), 1);
>> +   if (ret)
>> +   goto out;
>> +
>> +   ret = ufshcd_dme_set(hba, UIC_ARG_MIB(T_PEERCPORTID), 0);
>> +   if (ret)
>> +   goto out;
>> +
>> +   ret = ufshcd_dme_set(hba, UIC_ARG_MIB(T_TRAFFICCLASS), 0);
>> +   if (ret)
>> +   goto out;
>> +
>> +   ret = ufshcd_dme_set(hba, UIC_ARG_MIB(T_CPORTFLAGS), 0x6);
>> +   if (ret)
>> +   goto out;
>> +
>> +   ret = ufshcd_dme_set(hba, UIC_ARG_MIB(T_CPORTMODE), 1);
>> +   if (ret)
>> +   goto out;
>> +
>> +   ret = ufshcd_dme_set(hba, UIC_ARG_MIB(T_CONNECTIONSTATE), 1);
>> +   if (ret)
>> +   goto out;
>> +
>> +
>> +   /* Peer side Configuration */
>> +   ret = ufshcd_dme_peer_set(hba, UIC_ARG_MIB(T_CONNECTIONSTATE), 0);
>> +   if (ret)
>> +   goto out;
>> +
>> +   ret = ufshcd_dme_peer_set(hba, UIC_ARG_MIB(N_DEVICEID), 1);
>> +   if (ret)
>> +   goto out;
>> +
>> +   ret = ufshcd_dme_peer_set(hba, UIC_ARG_MIB(N_DEVICEID_VALID), 1);
>> +   if (ret)
>> +   goto out;
>> +
>> +   ret = ufshcd_dme_peer_set(hba, UIC_ARG_MIB(T_PEERDEVICEID), 1);
>> +   if (ret)
>> +   goto out;
>> +
>> +   ret = ufshcd_dme_peer_set(hba, UIC_ARG_MIB(T_PEERCPORTID), 0);
>> +   if (ret)
>> +   goto out;
>> +
>> +   ret = ufshcd_dme_peer_set(hba, UIC_ARG_MIB(T_TRAFFICCLASS), 0);
>> +   if (ret)
>> +   goto out;
>> +
>> +   ret = ufshcd_dme_peer_set(hba, UIC_ARG_MIB(T_CPORTFLAGS), 0x6);
>> +   if (ret)
>> +   goto out;
>> +
>> +   ret = ufshcd_dme_peer_set(hba, UIC_ARG_MIB(T_CPORTMODE), 1);
>> +   if (ret)
>> +   goto out;
>> +
>> +   ret = ufshcd_dme_peer_set(hba, UIC_ARG_MIB(T_CONNECTIONSTATE), 1);
>> +   if (ret)
>> +   goto out;
>> +
>> +out:
>> +   return ret;
>> +}
> 
> This looks a bit redundant.  The most part of the functions in this file is
> doing ufshcd_dme_set() or ufshcd_dme_peer_set(), so should we
> introduce ufshcd_dme_set_attrs() like below?  It will also increase
> readability.

We can do that, it would make the function body lighter and more easy to read I
agree with you!

> 
> struct ufshcd_dme_attr_val {
> u32 attr_sel;
> u32 mib_val;
> u8 peer;
> };
> 
> int ufshcd_dme_set_attrs(struct ufs_hba *hba,
> const struct ufshcd_dme_attr_val *v, int n)
> {
> for (i = 0; i < n; i++) {
> int ret = ufshcd_dme_set_attr(hba, v[i].attr_sel, ...);
> 
> if (ret)
> return ret;
> }
> return 0;
> }
> 
> static int ufshcd_dwc_connection_setup(struct ufs_hba *hba)
> {
> const struct ufshcd_dme_attr setup_attrs[] = {
> { UIC_ARG_MIB(T_CONNECTIONSTATE), 0, DME_LOCAL },
> { UIC_ARG_MIB(T_DEVICEID), 0, DME_LOCAL },
> ...
> };
> 
> return ufshcd_dme_set_attrs(hba, setup_attrs, 
> ARRAY_SIZE(setup_attrs));
> }
> 
>> +static int ufshcd_dwc_setup_tc(struct ufs_hba *hba)
>> +{
>> +   int ret = 0;
>> +
>> +#ifdef CONFIG_SCSI_UFS_DWC_40BIT_RMMI
>> +   dev_info(hba->dev, "Configuring Test Chip 40-bit RMMI");
>> +   ret = ufshcd_dwc_setup_40bit_rmmi(hba);
>> +   if (ret) {
>> +   dev_err(hba->dev, "Configuration failed");
> 
> Please add \n in the end of message.
> (and there are same issues in this file)
> 
>> +
>> +/* Clock Divider Values: Hex equivalent of frequency in MHz */
>> +enum clk_div_values {
>> +   UFSHCD_CLK_DIV_62_5 = 0x3e,
>> +   UFSHCD_CLK_DIV_125  = 0x7d,
>> +   UFSHCD_CLK_DIV_200  = 0xc8,
>> +};
> 
> This is used as register value for DWC_UFS_REG_HCLKDIV.  So should they
> have similar prefix (DWC_UFS_REG_HCLKDIV_*)?

I agree with you, they should have since they are DWC specific.

> 
>> diff --git a/drivers/scsi/ufs/unipro.h b/drivers/scsi/ufs/unipro.h
> 
> ...
> 
>> +/*Other attributes*/
>> +#define VS_MPHYCFGUPDT 0xD085
>> +#define VS_DEBUGOMC0xD09E
>> +#define VS_POWERSTATE  0xD083
> 
> Are these vendor specific attributes?  If so, please move them to
> ufshci-dwc.h.

These are not DWC specific, 

[PATCHv7 06/23] scsi_dh_alua: allocate RTPG buffer separately

2016-02-15 Thread Hannes Reinecke
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, _hdr, h->flags);
+   retval = submit_rtpg(sdev, buff, bufflen, _hdr, h->flags);
 
if (retval) {
if (!scsi_sense_valid(_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, _hdr);
+   kfree(buff);
return SCSI_DH_IO;
}
 
-   len = get_unaligned_be32(>buff[0]) + 4;
+   len = get_unaligned_be32([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)) {

[PATCHv7 00/23] ALUA device handler update, part II

2016-02-15 Thread Hannes Reinecke
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.

The entire patchset can be found at:
git.kernel.org:/hare/scsi-devel/h/alua-2.v7

As usual, comments and reviews are welcome.

Changes to v6:
- Fixup mutex lockdep issue noticed by Bart
- Reshuffle locks in alua_check_vpd

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 | 981 -
 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, 755 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


[PATCHv7 03/23] scsi_dh_alua: Make stpg synchronous

2016-02-15 Thread Hannes Reinecke
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,
-_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, _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, >buff[6]);
+   memset(stpg_data, 0, stpg_len);
+   stpg_data[4] = TPGS_STATE_OPTIMIZED & 0x0f;
+   put_unaligned_be16(group_id, _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, >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 

[PATCHv7 04/23] scsi_dh_alua: call alua_rtpg() if stpg fails

2016-02-15 Thread Hannes Reinecke
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


[PATCHv7 17/23] scsi_dh_alua: update all port states

2016-02-15 Thread Hannes Reinecke
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 c09a523..6de9261 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([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([2]);
+
+   spin_lock_irqsave(_group_lock, flags);
+   tmp_pg = alua_find_get_pg(pg->device_id_str, pg->device_id_len,
+ group_id);
+   spin_unlock_irqrestore(_group_lock, flags);
+   if (tmp_pg) {
+   if (spin_trylock_irqsave(_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(_pg->lock, flags);
+   }
+   kref_put(_pg->kref, release_port_group);
}
-   off = 8 + (ucp[7] * 4);
+   off = 8 + (desc[7] * 4);
}
 
+   spin_lock_irqsave(>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(>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


[PATCHv7 14/23] scsi_dh_alua: Allow workqueue to run synchronously

2016-02-15 Thread Hannes Reinecke
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(>lock, flags);
sdev = pg->rtpg_sdev;
@@ -697,6 +700,8 @@ static void alua_rtpg_work(struct work_struct *work)
spin_unlock_irqrestore(>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(>lock, flags);
-   queue_delayed_work(kaluad_wq, >rtpg_work,
+   queue_delayed_work(alua_wq, >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(>lock, flags);
-   queue_delayed_work(kaluad_wq, >rtpg_work,
+   queue_delayed_work(alua_wq, >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(>lock, flags);
 
if (start_queue &&
-   !queue_delayed_work(kaluad_wq, >rtpg_work,
+   !queue_delayed_work(alua_wq, >rtpg_work,
msecs_to_jiffies(ALUA_RTPG_DELAY_MSECS))) {
scsi_device_put(sdev);
kref_put(>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(_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(_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


[PATCHv7 09/23] scsi_dh_alua: simplify alua_initialize()

2016-02-15 Thread Hannes Reinecke
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(>pg->kref);
-   err = alua_rtpg(sdev, h->pg, 0);
-   kref_put(>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


[PATCHv7 19/23] scsi_dh: add 'rescan' callback

2016-02-15 Thread Hannes Reinecke
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 e3d7ba7..429c34d 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -1028,6 +1028,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
@@ -1088,6 +1095,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_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


[PATCHv7 12/23] scsi_dh_alua: remove 'rel_port' from alua_dh_data structure

2016-02-15 Thread Hannes Reinecke
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


[PATCHv7 16/23] scsi_dh_alua: Recheck state on unit attention

2016-02-15 Thread Hannes Reinecke
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 | 67 --
 1 file changed, 55 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..c09a523 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(>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(>lock, flags);
err = alua_rtpg(sdev, pg);
spin_lock_irqsave(>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(>lock, flags);
@@ -726,7 +737,7 @@ static void alua_rtpg_work(struct work_struct *work)
spin_unlock_irqrestore(>lock, flags);
err = alua_stpg(sdev, pg);
spin_lock_irqsave(>lock, flags);
-   if (err == SCSI_DH_RETRY) {
+   if (err == SCSI_DH_RETRY || pg->flags & ALUA_PG_RUN_RTPG) {
pg->flags |= ALUA_PG_RUN_RTPG;

[PATCHv7 23/23] scsi_dh_alua: Update version to 2.0

2016-02-15 Thread Hannes Reinecke
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 3199aef..c718318 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


[PATCHv7 05/23] scsi_dh_alua: switch to scsi_execute_req_flags()

2016-02-15 Thread Hannes Reinecke
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, >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, [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);

[PATCHv7 07/23] scsi_dh_alua: Use separate alua_port_group structure

2016-02-15 Thread Hannes Reinecke
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(_group_lock);
+   list_del(>node);
+   spin_unlock(_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(>kref);
+   spin_lock(_group_lock);
+   list_add(>node, _group_list);
+   spin_unlock(_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, _hdr, h->flags);
+   retval = submit_rtpg(sdev, buff, bufflen, _hdr, pg->flags);
 
if (retval) {
if (!scsi_sense_valid(_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.asc == 

[PATCHv7 22/23] scsi_dh_alua: update 'access_state' field

2016-02-15 Thread Hannes Reinecke
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 cd636bc..3199aef 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(>rtpg_work, alua_rtpg_work);
INIT_LIST_HEAD(>rtpg_list);
INIT_LIST_HEAD(>node);
+   INIT_LIST_HEAD(>dh_list);
spin_lock_init(>lock);
 
spin_lock(_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, _port);
if (group_id < 0) {
@@ -357,10 +363,22 @@ 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(_pg->lock, flags);
+   list_del_rcu(>node);
+   spin_unlock_irqrestore(_pg->lock, flags);
+   }
rcu_assign_pointer(h->pg, pg);
+   pg_updated = true;
}
+
+   spin_lock_irqsave(>lock, flags);
if (sdev->synchronous_alua)
pg->flags |= ALUA_SYNC_STPG;
+   if (pg_updated)
+   list_add_rcu(>node, >dh_list);
+   spin_unlock_irqrestore(>lock, flags);
+
alua_rtpg_queue(h->pg, sdev, NULL, true);
spin_unlock(>pg_lock);
 
@@ -613,8 +631,18 @@ static int alua_rtpg(struct scsi_device *sdev, struct 
alua_port_group *pg)
if (spin_trylock_irqsave(_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,
+   _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, >dh_list, node) {
+   BUG_ON(!h->sdev);
+   h->sdev->access_state =
+   (pg->state & SCSI_ACCESS_STATE_MASK);
+   if (pg->pref)
+   h->sdev->access_state |=
+   SCSI_ACCESS_STATE_PREFERRED;
+   }
+   rcu_read_unlock();
}

[PATCHv7 21/23] scsi_dh_alua: use common definitions for ALUA state

2016-02-15 Thread Hannes Reinecke
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 429c34d..cd636bc 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, _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(>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_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 

[PATCHv7 01/23] scsi_dh_alua: Pass buffer as function argument

2016-02-15 Thread Hannes Reinecke
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, >cmd[6]);
+   put_unaligned_be32(bufflen, >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,
  _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


[PATCHv7 15/23] scsi_dh_alua: Add new blacklist flag 'BLIST_SYNC_ALUA'

2016-02-15 Thread Hannes Reinecke
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(>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


[PATCHv7 20/23] scsi: Add 'access_state' attribute

2016-02-15 Thread Hannes Reinecke
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(>siblings);
INIT_LIST_HEAD(>same_target_siblings);
INIT_LIST_HEAD(>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[] = {
_attr_wwid.attr,
 #ifdef CONFIG_SCSI_DH
_attr_dh_state.attr,
+   _attr_access_state.attr,
 #endif
_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


[PATCHv7 10/23] revert commit a8e5a2d593cb ("[SCSI] scsi_dh_alua: ALUA handler attach should succeed while TPG is transitioning")

2016-02-15 Thread Hannes Reinecke
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(>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(>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


[PATCHv7 08/23] scsi_dh_alua: use unique device id

2016-02-15 Thread Hannes Reinecke
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, _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(>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(>kref);
+
spin_lock(_group_lock);
+   tmp_pg = alua_find_get_pg(pg->device_id_str, pg->device_id_len,
+ group_id);
+   if (tmp_pg) {
+   spin_unlock(_group_lock);
+   kfree(pg);
+   return tmp_pg;
+   }
+
list_add(>node, _group_list);
spin_unlock(_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(>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


[PATCHv7 02/23] scsi_dh_alua: separate out alua_stpg()

2016-02-15 Thread Hannes Reinecke
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