Commit 19c8ead7 authored by Ewan D. Milne's avatar Ewan D. Milne Committed by Christoph Hellwig

scsi_debug: Add REPORTED LUNS DATA HAS CHANGED Unit Attention

Generate a REPORTED LUNS DATA HAS CHANGED Unit Attention if
sysfs "max_luns" is used to change the number of scsi_debug LUNs.
This is only done if scsi_debug_scsi_level is SPC-3 or above.
Additionally, implement SPC-4 behavior which only generates
this Unit Attention on the first LUN on the target to receive
a command after the change.  This condition is cleared when
a REPORT LUNS command is received.
Signed-off-by: default avatarEwan D. Milne <emilne@redhat.com>
Acked-by: default avatarDouglas Gilbert <dgilbert@interlog.com>
Tested-by: default avatarDouglas Gilbert <dgilbert@interlog.com>
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
parent 08024885
...@@ -80,6 +80,8 @@ static const char *scsi_debug_version_date = "20141022"; ...@@ -80,6 +80,8 @@ static const char *scsi_debug_version_date = "20141022";
#define INVALID_FIELD_IN_PARAM_LIST 0x26 #define INVALID_FIELD_IN_PARAM_LIST 0x26
#define UA_RESET_ASC 0x29 #define UA_RESET_ASC 0x29
#define UA_CHANGED_ASC 0x2a #define UA_CHANGED_ASC 0x2a
#define TARGET_CHANGED_ASC 0x3f
#define LUNS_CHANGED_ASCQ 0x0e
#define INSUFF_RES_ASC 0x55 #define INSUFF_RES_ASC 0x55
#define INSUFF_RES_ASCQ 0x3 #define INSUFF_RES_ASCQ 0x3
#define POWER_ON_RESET_ASCQ 0x0 #define POWER_ON_RESET_ASCQ 0x0
...@@ -180,7 +182,8 @@ static const char *scsi_debug_version_date = "20141022"; ...@@ -180,7 +182,8 @@ static const char *scsi_debug_version_date = "20141022";
#define SDEBUG_UA_BUS_RESET 1 #define SDEBUG_UA_BUS_RESET 1
#define SDEBUG_UA_MODE_CHANGED 2 #define SDEBUG_UA_MODE_CHANGED 2
#define SDEBUG_UA_CAPACITY_CHANGED 3 #define SDEBUG_UA_CAPACITY_CHANGED 3
#define SDEBUG_NUM_UAS 4 #define SDEBUG_UA_LUNS_CHANGED 4
#define SDEBUG_NUM_UAS 5
/* for check_readiness() */ /* for check_readiness() */
#define UAS_ONLY 1 /* check for UAs only */ #define UAS_ONLY 1 /* check for UAs only */
...@@ -782,6 +785,22 @@ static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg) ...@@ -782,6 +785,22 @@ static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
/* return -ENOTTY; // correct return but upsets fdisk */ /* return -ENOTTY; // correct return but upsets fdisk */
} }
static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
{
struct sdebug_host_info *sdhp;
struct sdebug_dev_info *dp;
spin_lock(&sdebug_host_list_lock);
list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
if ((devip->sdbg_host == dp->sdbg_host) &&
(devip->target == dp->target))
clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
}
}
spin_unlock(&sdebug_host_list_lock);
}
static int check_readiness(struct scsi_cmnd *SCpnt, int uas_only, static int check_readiness(struct scsi_cmnd *SCpnt, int uas_only,
struct sdebug_dev_info * devip) struct sdebug_dev_info * devip)
{ {
...@@ -817,6 +836,23 @@ static int check_readiness(struct scsi_cmnd *SCpnt, int uas_only, ...@@ -817,6 +836,23 @@ static int check_readiness(struct scsi_cmnd *SCpnt, int uas_only,
if (debug) if (debug)
cp = "capacity data changed"; cp = "capacity data changed";
break; break;
case SDEBUG_UA_LUNS_CHANGED:
/*
* SPC-3 behavior is to report a UNIT ATTENTION with
* ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
* on the target, until a REPORT LUNS command is
* received. SPC-4 behavior is to report it only once.
* NOTE: scsi_debug_scsi_level does not use the same
* values as struct scsi_device->scsi_level.
*/
if (scsi_debug_scsi_level >= 6) /* SPC-4 and above */
clear_luns_changed_on_target(devip);
mk_sense_buffer(SCpnt, UNIT_ATTENTION,
TARGET_CHANGED_ASC,
LUNS_CHANGED_ASCQ);
if (debug)
cp = "reported luns data has changed";
break;
default: default:
pr_warn("%s: unexpected unit attention code=%d\n", pr_warn("%s: unexpected unit attention code=%d\n",
__func__, k); __func__, k);
...@@ -3229,6 +3265,7 @@ static int resp_report_luns(struct scsi_cmnd * scp, ...@@ -3229,6 +3265,7 @@ static int resp_report_luns(struct scsi_cmnd * scp,
unsigned char arr[SDEBUG_RLUN_ARR_SZ]; unsigned char arr[SDEBUG_RLUN_ARR_SZ];
unsigned char * max_addr; unsigned char * max_addr;
clear_luns_changed_on_target(devip);
alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24); alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
shortish = (alloc_len < 4); shortish = (alloc_len < 4);
if (shortish || (select_report > 2)) { if (shortish || (select_report > 2)) {
...@@ -4369,10 +4406,27 @@ static ssize_t max_luns_store(struct device_driver *ddp, const char *buf, ...@@ -4369,10 +4406,27 @@ static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
size_t count) size_t count)
{ {
int n; int n;
bool changed;
if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
changed = (scsi_debug_max_luns != n);
scsi_debug_max_luns = n; scsi_debug_max_luns = n;
sdebug_max_tgts_luns(); sdebug_max_tgts_luns();
if (changed && (scsi_debug_scsi_level >= 5)) { /* >= SPC-3 */
struct sdebug_host_info *sdhp;
struct sdebug_dev_info *dp;
spin_lock(&sdebug_host_list_lock);
list_for_each_entry(sdhp, &sdebug_host_list,
host_list) {
list_for_each_entry(dp, &sdhp->dev_info_list,
dev_list) {
set_bit(SDEBUG_UA_LUNS_CHANGED,
dp->uas_bm);
}
}
spin_unlock(&sdebug_host_list_lock);
}
return count; return count;
} }
return -EINVAL; return -EINVAL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment