mirror of
https://github.com/SCST-project/scst.git
synced 2026-05-17 18:51:27 +00:00
- Added "replace" command to replace one LUN by another and generate INQUIRY DATA HAS CHANGED Unit Attention
- Sending INQUIRY DATA HAS CHANGED Unit Attention through AENs added - Minor fixes and cleanups git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@1036 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
15
scst/README
15
scst/README
@@ -460,6 +460,14 @@ following files and directories under /proc/scsi_tgt:
|
||||
the device could be marked as read only. The recommended way to find out
|
||||
H:C:I:L numbers is use of lsscsi utility.
|
||||
|
||||
- "replace H:C:I:L lun [READ_ONLY]" to /proc/scsi_tgt/groups/GROUP_NAME/devices
|
||||
replaces by device with host:channel:id:lun existing with LUN "lun"
|
||||
device in group "GROUP_NAME" with generation of INQUIRY DATA HAS
|
||||
CHANGED Unit Attention. If the old device doesn't exist, this
|
||||
command acts as the "add" command. Optionally, the device could be
|
||||
marked as read only. The recommended way to find out H:C:I:L numbers
|
||||
is use of lsscsi utility.
|
||||
|
||||
- "del H:C:I:L" to /proc/scsi_tgt/groups/GROUP_NAME/devices deletes device with
|
||||
host:channel:id:lun from group "GROUP_NAME". The recommended way to find out
|
||||
H:C:I:L numbers is use of lsscsi utility.
|
||||
@@ -468,6 +476,13 @@ following files and directories under /proc/scsi_tgt:
|
||||
device with virtual name "V_NAME" with LUN "lun" in group "GROUP_NAME".
|
||||
Optionally, the device could be marked as read only.
|
||||
|
||||
- "replace V_NAME lun [READ_ONLY]" to /proc/scsi_tgt/groups/GROUP_NAME/devices
|
||||
replaces by device with virtual name "V_NAME" existing with LUN
|
||||
"lun" device in group "GROUP_NAME" with generation of INQUIRY DATA
|
||||
HAS CHANGED Unit Attention. If the old device doesn't exist, this
|
||||
command acts as the "add" command. Optionally, the device could
|
||||
be marked as read only.
|
||||
|
||||
- "del V_NAME" to /proc/scsi_tgt/groups/GROUP_NAME/devices deletes device with
|
||||
virtual name "V_NAME" from group "GROUP_NAME"
|
||||
|
||||
|
||||
@@ -378,13 +378,28 @@ following files and directories under /proc/scsi_tgt:
|
||||
the device could be marked as read only. The recommended way to find out
|
||||
H:C:I:L numbers is use of lsscsi utility.
|
||||
|
||||
- "replace H:C:I:L lun [READ_ONLY]" to /proc/scsi_tgt/groups/GROUP_NAME/devices
|
||||
replaces by device with host:channel:id:lun existing with LUN "lun"
|
||||
device in group "GROUP_NAME" with generation of INQUIRY DATA HAS
|
||||
CHANGED Unit Attention. If the old device doesn't exist, this
|
||||
command acts as the "add" command. Optionally, the device could be
|
||||
marked as read only. The recommended way to find out H:C:I:L numbers
|
||||
is use of lsscsi utility.
|
||||
|
||||
- "del H:C:I:L" to /proc/scsi_tgt/groups/GROUP_NAME/devices deletes device with
|
||||
host:channel:id:lun from group "GROUP_NAME". The recommended way to find out
|
||||
H:C:I:L numbers is use of lsscsi utility.
|
||||
|
||||
- "add V_NAME lun [READ_ONLY]" to /proc/scsi_tgt/groups/GROUP_NAME/devices adds
|
||||
device with virtual name "V_NAME" with LUN "lun" in group "GROUP_NAME".
|
||||
Optionally, the device could be marked as read only.
|
||||
device with virtual name "V_NAME" with LUN "lun" in group
|
||||
"GROUP_NAME". Optionally, the device could be marked as read only.
|
||||
|
||||
- "replace V_NAME lun [READ_ONLY]" to /proc/scsi_tgt/groups/GROUP_NAME/devices
|
||||
replaces by device with virtual name "V_NAME" existing with LUN
|
||||
"lun" device in group "GROUP_NAME" with generation of INQUIRY DATA
|
||||
HAS CHANGED Unit Attention. If the old device doesn't exist, this
|
||||
command acts as the "add" command. Optionally, the device could be
|
||||
marked as read only.
|
||||
|
||||
- "del V_NAME" to /proc/scsi_tgt/groups/GROUP_NAME/devices deletes device with
|
||||
virtual name "V_NAME" from group "GROUP_NAME"
|
||||
|
||||
@@ -410,7 +410,8 @@ void scst_set_initial_UA(struct scst_session *sess, int key, int asc, int ascq)
|
||||
}
|
||||
EXPORT_SYMBOL(scst_set_initial_UA);
|
||||
|
||||
static struct scst_aen *scst_alloc_aen(struct scst_tgt_dev *tgt_dev)
|
||||
static struct scst_aen *scst_alloc_aen(struct scst_session *sess,
|
||||
uint64_t unpacked_lun)
|
||||
{
|
||||
struct scst_aen *aen;
|
||||
|
||||
@@ -420,15 +421,15 @@ static struct scst_aen *scst_alloc_aen(struct scst_tgt_dev *tgt_dev)
|
||||
if (aen == NULL) {
|
||||
PRINT_ERROR("AEN memory allocation failed. Corresponding "
|
||||
"event notification will not be performed (initiator "
|
||||
"%s)", tgt_dev->sess->initiator_name);
|
||||
"%s)", sess->initiator_name);
|
||||
goto out;
|
||||
}
|
||||
memset(aen, 0, sizeof(*aen));
|
||||
|
||||
aen->sess = tgt_dev->sess;
|
||||
scst_sess_get(aen->sess);
|
||||
aen->sess = sess;
|
||||
scst_sess_get(sess);
|
||||
|
||||
aen->lun = scst_pack_lun(tgt_dev->lun);
|
||||
aen->lun = scst_pack_lun(unpacked_lun);
|
||||
|
||||
out:
|
||||
TRACE_EXIT_HRES((unsigned long)aen);
|
||||
@@ -446,11 +447,55 @@ static void scst_free_aen(struct scst_aen *aen)
|
||||
return;
|
||||
};
|
||||
|
||||
/* Must be called unded scst_mutex */
|
||||
void scst_gen_aen_or_ua(struct scst_tgt_dev *tgt_dev,
|
||||
int key, int asc, int ascq)
|
||||
{
|
||||
struct scst_tgt_template *tgtt = tgt_dev->sess->tgt->tgtt;
|
||||
uint8_t sense_buffer[SCST_STANDARD_SENSE_LEN];
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
if (tgtt->report_aen != NULL) {
|
||||
struct scst_aen *aen;
|
||||
int rc;
|
||||
|
||||
aen = scst_alloc_aen(tgt_dev->sess, tgt_dev->lun);
|
||||
if (aen == NULL)
|
||||
goto queue_ua;
|
||||
|
||||
aen->event_fn = SCST_AEN_SCSI;
|
||||
aen->aen_sense_len = SCST_STANDARD_SENSE_LEN;
|
||||
scst_set_sense(aen->aen_sense, aen->aen_sense_len,
|
||||
tgt_dev->dev->d_sense, key, asc, ascq);
|
||||
|
||||
TRACE_DBG("Calling target's %s report_aen(%p)",
|
||||
tgtt->name, aen);
|
||||
rc = tgtt->report_aen(aen);
|
||||
TRACE_DBG("Target's %s report_aen(%p) returned %d",
|
||||
tgtt->name, aen, rc);
|
||||
if (rc == SCST_AEN_RES_SUCCESS)
|
||||
goto out;
|
||||
|
||||
scst_free_aen(aen);
|
||||
}
|
||||
|
||||
queue_ua:
|
||||
TRACE_MGMT_DBG("AEN not supported, queuing plain UA (tgt_dev %p)",
|
||||
tgt_dev);
|
||||
scst_set_sense(sense_buffer, sizeof(sense_buffer),
|
||||
tgt_dev->dev->d_sense, key, asc, ascq);
|
||||
scst_check_set_UA(tgt_dev, sense_buffer, sizeof(sense_buffer), 0);
|
||||
|
||||
out:
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
}
|
||||
|
||||
/* No locks */
|
||||
void scst_capacity_data_changed(struct scst_device *dev)
|
||||
{
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
uint8_t sense_buffer[SCST_STANDARD_SENSE_LEN];
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
@@ -466,40 +511,8 @@ void scst_capacity_data_changed(struct scst_device *dev)
|
||||
|
||||
list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list,
|
||||
dev_tgt_dev_list_entry) {
|
||||
struct scst_tgt_template *tgtt = tgt_dev->sess->tgt->tgtt;
|
||||
|
||||
if (tgtt->report_aen != NULL) {
|
||||
struct scst_aen *aen;
|
||||
int rc;
|
||||
|
||||
aen = scst_alloc_aen(tgt_dev);
|
||||
if (aen == NULL)
|
||||
goto queue_ua;
|
||||
|
||||
aen->event_fn = SCST_AEN_SCSI;
|
||||
aen->aen_sense_len = SCST_STANDARD_SENSE_LEN;
|
||||
scst_set_sense(aen->aen_sense, aen->aen_sense_len,
|
||||
tgt_dev->dev->d_sense,
|
||||
SCST_LOAD_SENSE(scst_sense_capacity_data_changed));
|
||||
|
||||
TRACE_DBG("Calling target's %s report_aen(%p)",
|
||||
tgtt->name, aen);
|
||||
rc = tgtt->report_aen(aen);
|
||||
TRACE_DBG("Target's %s report_aen(%p) returned %d",
|
||||
tgtt->name, aen, rc);
|
||||
if (rc == SCST_AEN_RES_SUCCESS)
|
||||
continue;
|
||||
|
||||
scst_free_aen(aen);
|
||||
}
|
||||
queue_ua:
|
||||
TRACE_MGMT_DBG("Queuing CAPACITY DATA CHANGED UA (tgt_dev %p)",
|
||||
tgt_dev);
|
||||
scst_set_sense(sense_buffer, sizeof(sense_buffer),
|
||||
tgt_dev->dev->d_sense,
|
||||
scst_gen_aen_or_ua(tgt_dev,
|
||||
SCST_LOAD_SENSE(scst_sense_capacity_data_changed));
|
||||
scst_check_set_UA(tgt_dev, sense_buffer,
|
||||
sizeof(sense_buffer), 0);
|
||||
}
|
||||
|
||||
mutex_unlock(&scst_mutex);
|
||||
@@ -594,41 +607,43 @@ static void scst_queue_report_luns_changed_UA(struct scst_session *sess,
|
||||
static void scst_report_luns_changed_sess(struct scst_session *sess)
|
||||
{
|
||||
int i;
|
||||
struct list_head *shead;
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
struct scst_tgt_template *tgtt = sess->tgt->tgtt;
|
||||
int d_sense = 0;
|
||||
uint64_t lun = 0;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
TRACE_DBG("REPORTED LUNS DATA CHANGED (sess %p)", sess);
|
||||
|
||||
for (i = 0; i < TGT_DEV_HASH_SIZE; i++) {
|
||||
struct list_head *shead;
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
|
||||
shead = &sess->sess_tgt_dev_list_hash[i];
|
||||
|
||||
list_for_each_entry(tgt_dev, shead,
|
||||
sess_tgt_dev_list_entry) {
|
||||
if (scst_is_report_luns_changed_type(
|
||||
tgt_dev->dev->type))
|
||||
tgt_dev->dev->type)) {
|
||||
lun = tgt_dev->lun;
|
||||
d_sense = tgt_dev->dev->d_sense;
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
}
|
||||
TRACE_MGMT_DBG("Not found a device capable REPORTED "
|
||||
"LUNS DATA CHANGED UA (sess %p)", sess);
|
||||
goto out;
|
||||
|
||||
found:
|
||||
if (tgtt->report_aen != NULL) {
|
||||
struct scst_aen *aen;
|
||||
int rc;
|
||||
|
||||
aen = scst_alloc_aen(tgt_dev);
|
||||
aen = scst_alloc_aen(sess, lun);
|
||||
if (aen == NULL)
|
||||
goto queue_ua;
|
||||
|
||||
aen->event_fn = SCST_AEN_SCSI;
|
||||
aen->aen_sense_len = SCST_STANDARD_SENSE_LEN;
|
||||
scst_set_sense(aen->aen_sense, aen->aen_sense_len,
|
||||
tgt_dev->dev->d_sense,
|
||||
scst_set_sense(aen->aen_sense, aen->aen_sense_len, d_sense,
|
||||
SCST_LOAD_SENSE(scst_sense_reported_luns_data_changed));
|
||||
|
||||
TRACE_DBG("Calling target's %s report_aen(%p)",
|
||||
@@ -690,10 +705,7 @@ void scst_aen_done(struct scst_aen *aen)
|
||||
scst_queue_report_luns_changed_UA(aen->sess,
|
||||
SCST_SET_UA_FLAG_AT_HEAD);
|
||||
mutex_unlock(&scst_mutex);
|
||||
} else if (scst_analyze_sense(aen->aen_sense, aen->aen_sense_len,
|
||||
SCST_SENSE_ALL_VALID,
|
||||
SCST_LOAD_SENSE(scst_sense_capacity_data_changed))) {
|
||||
/* tgt_dev might get dead, so we need to reseek it */
|
||||
} else {
|
||||
struct list_head *shead;
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
uint64_t lun;
|
||||
@@ -702,12 +714,13 @@ void scst_aen_done(struct scst_aen *aen)
|
||||
|
||||
mutex_lock(&scst_mutex);
|
||||
|
||||
/* tgt_dev might get dead, so we need to reseek it */
|
||||
shead = &aen->sess->sess_tgt_dev_list_hash[HASH_VAL(lun)];
|
||||
list_for_each_entry(tgt_dev, shead,
|
||||
sess_tgt_dev_list_entry) {
|
||||
if (tgt_dev->lun == lun) {
|
||||
TRACE_MGMT_DBG("Queuing CAPACITY DATA CHANGED "
|
||||
"UA (tgt_dev %p)", tgt_dev);
|
||||
TRACE_MGMT_DBG("Requeuing failed AEN UA for "
|
||||
"tgt_dev %p", tgt_dev);
|
||||
scst_check_set_UA(tgt_dev, aen->aen_sense,
|
||||
aen->aen_sense_len,
|
||||
SCST_SET_UA_FLAG_AT_HEAD);
|
||||
@@ -716,8 +729,7 @@ void scst_aen_done(struct scst_aen *aen)
|
||||
}
|
||||
|
||||
mutex_unlock(&scst_mutex);
|
||||
} else
|
||||
PRINT_ERROR("%s", "Unknown SCSI AEN");
|
||||
}
|
||||
|
||||
out_free:
|
||||
scst_free_aen(aen);
|
||||
@@ -851,8 +863,6 @@ next:
|
||||
list_move_tail(&sess->acg_sess_list_entry, &acg->acg_sess_list);
|
||||
|
||||
if (luns_changed) {
|
||||
uint8_t sense_buffer[SCST_STANDARD_SENSE_LEN];
|
||||
|
||||
scst_report_luns_changed_sess(sess);
|
||||
|
||||
for (i = 0; i < TGT_DEV_HASH_SIZE; i++) {
|
||||
@@ -867,13 +877,8 @@ next:
|
||||
|
||||
tgt_dev->inq_changed_ua_needed = 0;
|
||||
|
||||
scst_set_sense(sense_buffer,
|
||||
sizeof(sense_buffer),
|
||||
tgt_dev->dev->d_sense,
|
||||
scst_gen_aen_or_ua(tgt_dev,
|
||||
SCST_LOAD_SENSE(scst_sense_inquery_data_changed));
|
||||
|
||||
scst_check_set_UA(tgt_dev, sense_buffer,
|
||||
sizeof(sense_buffer), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1729,7 +1734,7 @@ static void scst_sess_free_tgt_devs(struct scst_session *sess)
|
||||
|
||||
/* The activity supposed to be suspended and scst_mutex held */
|
||||
int scst_acg_add_dev(struct scst_acg *acg, struct scst_device *dev,
|
||||
uint64_t lun, int read_only)
|
||||
uint64_t lun, int read_only, bool gen_scst_report_luns_changed)
|
||||
{
|
||||
int res = 0;
|
||||
struct scst_acg_dev *acg_dev;
|
||||
@@ -1741,17 +1746,6 @@ int scst_acg_add_dev(struct scst_acg *acg, struct scst_device *dev,
|
||||
|
||||
INIT_LIST_HEAD(&tmp_tgt_dev_list);
|
||||
|
||||
#ifdef CONFIG_SCST_EXTRACHECKS
|
||||
list_for_each_entry(acg_dev, &acg->acg_dev_list, acg_dev_list_entry) {
|
||||
if (acg_dev->dev == dev) {
|
||||
PRINT_ERROR("Device is already in group %s",
|
||||
acg->acg_name);
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
acg_dev = scst_alloc_acg_dev(acg, dev, lun);
|
||||
if (acg_dev == NULL) {
|
||||
res = -ENOMEM;
|
||||
@@ -1774,7 +1768,8 @@ int scst_acg_add_dev(struct scst_acg *acg, struct scst_device *dev,
|
||||
&tmp_tgt_dev_list);
|
||||
}
|
||||
|
||||
scst_report_luns_changed(acg);
|
||||
if (gen_scst_report_luns_changed)
|
||||
scst_report_luns_changed(acg);
|
||||
|
||||
if (dev->virt_name != NULL) {
|
||||
PRINT_INFO("Added device %s to group %s (LUN %lld, "
|
||||
@@ -1805,7 +1800,8 @@ out_free:
|
||||
}
|
||||
|
||||
/* The activity supposed to be suspended and scst_mutex held */
|
||||
int scst_acg_remove_dev(struct scst_acg *acg, struct scst_device *dev)
|
||||
int scst_acg_remove_dev(struct scst_acg *acg, struct scst_device *dev,
|
||||
bool gen_scst_report_luns_changed)
|
||||
{
|
||||
int res = 0;
|
||||
struct scst_acg_dev *acg_dev = NULL, *a;
|
||||
@@ -1833,7 +1829,8 @@ int scst_acg_remove_dev(struct scst_acg *acg, struct scst_device *dev)
|
||||
}
|
||||
scst_free_acg_dev(acg_dev);
|
||||
|
||||
scst_report_luns_changed(acg);
|
||||
if (gen_scst_report_luns_changed)
|
||||
scst_report_luns_changed(acg);
|
||||
|
||||
if (dev->virt_name != NULL) {
|
||||
PRINT_INFO("Removed device %s from group %s",
|
||||
|
||||
@@ -724,9 +724,8 @@ static void scst_unregister_device(struct scsi_device *scsidp)
|
||||
list_del(&dev->dev_list_entry);
|
||||
|
||||
list_for_each_entry_safe(acg_dev, aa, &dev->dev_acg_dev_list,
|
||||
dev_acg_dev_list_entry)
|
||||
{
|
||||
scst_acg_remove_dev(acg_dev->acg, dev);
|
||||
dev_acg_dev_list_entry) {
|
||||
scst_acg_remove_dev(acg_dev->acg, dev, true);
|
||||
}
|
||||
|
||||
scst_assign_dev_handler(dev, &scst_null_devtype);
|
||||
@@ -876,7 +875,7 @@ void scst_unregister_virtual_device(int id)
|
||||
list_for_each_entry_safe(acg_dev, aa, &dev->dev_acg_dev_list,
|
||||
dev_acg_dev_list_entry)
|
||||
{
|
||||
scst_acg_remove_dev(acg_dev->acg, dev);
|
||||
scst_acg_remove_dev(acg_dev->acg, dev, true);
|
||||
}
|
||||
|
||||
scst_assign_dev_handler(dev, &scst_null_devtype);
|
||||
|
||||
@@ -301,8 +301,9 @@ int scst_sess_alloc_tgt_devs(struct scst_session *sess);
|
||||
void scst_nexus_loss(struct scst_tgt_dev *tgt_dev, bool queue_UA);
|
||||
|
||||
int scst_acg_add_dev(struct scst_acg *acg, struct scst_device *dev,
|
||||
uint64_t lun, int read_only);
|
||||
int scst_acg_remove_dev(struct scst_acg *acg, struct scst_device *dev);
|
||||
uint64_t lun, int read_only, bool gen_scst_report_luns_changed);
|
||||
int scst_acg_remove_dev(struct scst_acg *acg, struct scst_device *dev,
|
||||
bool gen_scst_report_luns_changed);
|
||||
|
||||
int scst_acg_add_name(struct scst_acg *acg, const char *name);
|
||||
int scst_acg_remove_name(struct scst_acg *acg, const char *name, bool reassign);
|
||||
@@ -437,6 +438,9 @@ void scst_process_reset(struct scst_device *dev,
|
||||
bool scst_is_ua_global(const uint8_t *sense, int len);
|
||||
void scst_requeue_ua(struct scst_cmd *cmd);
|
||||
|
||||
void scst_gen_aen_or_ua(struct scst_tgt_dev *tgt_dev,
|
||||
int key, int asc, int ascq);
|
||||
|
||||
static inline bool scst_is_ua_command(struct scst_cmd *cmd)
|
||||
{
|
||||
return (cmd->op_flags & SCST_SKIP_UA) == 0;
|
||||
|
||||
@@ -80,11 +80,12 @@ static struct scst_proc_data scst_dev_handler_proc_data;
|
||||
#define SCST_PROC_ACTION_CLEAR 6
|
||||
#define SCST_PROC_ACTION_MOVE 7
|
||||
#define SCST_PROC_ACTION_DEL 8
|
||||
#define SCST_PROC_ACTION_VALUE 9
|
||||
#define SCST_PROC_ACTION_ASSIGN 10
|
||||
#define SCST_PROC_ACTION_ADD_GROUP 11
|
||||
#define SCST_PROC_ACTION_DEL_GROUP 12
|
||||
#define SCST_PROC_ACTION_RENAME_GROUP 13
|
||||
#define SCST_PROC_ACTION_REPLACE 9
|
||||
#define SCST_PROC_ACTION_VALUE 10
|
||||
#define SCST_PROC_ACTION_ASSIGN 11
|
||||
#define SCST_PROC_ACTION_ADD_GROUP 12
|
||||
#define SCST_PROC_ACTION_DEL_GROUP 13
|
||||
#define SCST_PROC_ACTION_RENAME_GROUP 14
|
||||
|
||||
static struct proc_dir_entry *scst_proc_scsi_tgt;
|
||||
static struct proc_dir_entry *scst_proc_groups_root;
|
||||
@@ -133,8 +134,12 @@ static char *scst_proc_help_string =
|
||||
"\n"
|
||||
" echo \"add|del H:C:I:L lun [READ_ONLY]\""
|
||||
" >/proc/scsi_tgt/groups/GROUP_NAME/devices\n"
|
||||
" echo \"replace H:C:I:L lun [READ_ONLY]\""
|
||||
" >/proc/scsi_tgt/groups/GROUP_NAME/devices\n"
|
||||
" echo \"add|del V_NAME lun [READ_ONLY]\""
|
||||
" >/proc/scsi_tgt/groups/GROUP_NAME/devices\n"
|
||||
" echo \"replace V_NAME lun [READ_ONLY]\""
|
||||
" >/proc/scsi_tgt/groups/GROUP_NAME/devices\n"
|
||||
" echo \"clear\" >/proc/scsi_tgt/groups/GROUP_NAME/devices\n"
|
||||
"\n"
|
||||
" echo \"add|del NAME\" >/proc/scsi_tgt/groups/GROUP_NAME/names\n"
|
||||
@@ -1613,8 +1618,12 @@ static ssize_t scst_proc_groups_devices_write(struct file *file,
|
||||
/*
|
||||
* Usage: echo "add|del H:C:I:L lun [READ_ONLY]" \
|
||||
* >/proc/scsi_tgt/groups/GROUP_NAME/devices
|
||||
* or echo "replace H:C:I:L lun [READ_ONLY]" \
|
||||
* >/proc/scsi_tgt/groups/GROUP_NAME/devices
|
||||
* or echo "add|del V_NAME lun [READ_ONLY]" \
|
||||
* >/proc/scsi_tgt/groups/GROUP_NAME/devices
|
||||
* or echo "replace V_NAME lun [READ_ONLY]" \
|
||||
* >/proc/scsi_tgt/groups/GROUP_NAME/devices
|
||||
* or echo "clear" >/proc/scsi_tgt/groups/GROUP_NAME/devices
|
||||
*/
|
||||
p = buffer;
|
||||
@@ -1628,6 +1637,9 @@ static ssize_t scst_proc_groups_devices_write(struct file *file,
|
||||
} else if (!strncasecmp("del ", p, 4)) {
|
||||
p += 4;
|
||||
action = SCST_PROC_ACTION_DEL;
|
||||
} else if (!strncasecmp("replace ", p, 8)) {
|
||||
p += 8;
|
||||
action = SCST_PROC_ACTION_REPLACE;
|
||||
} else {
|
||||
PRINT_ERROR("Unknown action \"%s\"", p);
|
||||
res = -EINVAL;
|
||||
@@ -1648,6 +1660,7 @@ static ssize_t scst_proc_groups_devices_write(struct file *file,
|
||||
switch (action) {
|
||||
case SCST_PROC_ACTION_ADD:
|
||||
case SCST_PROC_ACTION_DEL:
|
||||
case SCST_PROC_ACTION_REPLACE:
|
||||
while (isspace(*p) && *p != '\0')
|
||||
p++;
|
||||
e = p; /* save p */
|
||||
@@ -1703,6 +1716,10 @@ static ssize_t scst_proc_groups_devices_write(struct file *file,
|
||||
|
||||
switch (action) {
|
||||
case SCST_PROC_ACTION_ADD:
|
||||
case SCST_PROC_ACTION_REPLACE:
|
||||
{
|
||||
bool dev_replaced = false;
|
||||
|
||||
e++;
|
||||
while (isspace(*e) && *e != '\0')
|
||||
e++;
|
||||
@@ -1728,35 +1745,64 @@ static ssize_t scst_proc_groups_devices_write(struct file *file,
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (acg_dev) {
|
||||
acg_dev = acg_dev_tmp;
|
||||
PRINT_ERROR("virt lun %d already exists in group %s",
|
||||
virt_lun, acg->acg_name);
|
||||
res = -EINVAL;
|
||||
if (acg_dev != NULL) {
|
||||
if (action == SCST_PROC_ACTION_ADD) {
|
||||
PRINT_ERROR("virt lun %d already exists in "
|
||||
"group %s", virt_lun, acg->acg_name);
|
||||
res = -EINVAL;
|
||||
goto out_free_up;
|
||||
} else {
|
||||
/* Replace */
|
||||
rc = scst_acg_remove_dev(acg, acg_dev->dev,
|
||||
false);
|
||||
if (rc) {
|
||||
res = rc;
|
||||
goto out_free_up;
|
||||
}
|
||||
dev_replaced = true;
|
||||
}
|
||||
}
|
||||
|
||||
rc = scst_acg_add_dev(acg, dev, virt_lun, read_only,
|
||||
action == SCST_PROC_ACTION_ADD);
|
||||
if (rc) {
|
||||
res = rc;
|
||||
goto out_free_up;
|
||||
}
|
||||
rc = scst_acg_add_dev(acg, dev, virt_lun, read_only);
|
||||
if (rc) {
|
||||
PRINT_ERROR("scst_acg_add_dev() returned %d", rc);
|
||||
res = rc;
|
||||
|
||||
if (dev_replaced) {
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
|
||||
list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list,
|
||||
dev_tgt_dev_list_entry) {
|
||||
if ((tgt_dev->acg_dev->acg == acg) &&
|
||||
(tgt_dev->lun == virt_lun)) {
|
||||
TRACE_MGMT_DBG("INQUIRY DATA HAS CHANGED"
|
||||
" on tgt_dev %p", tgt_dev);
|
||||
scst_gen_aen_or_ua(tgt_dev,
|
||||
SCST_LOAD_SENSE(scst_sense_inquery_data_changed));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SCST_PROC_ACTION_DEL:
|
||||
rc = scst_acg_remove_dev(acg, dev);
|
||||
rc = scst_acg_remove_dev(acg, dev, true);
|
||||
if (rc) {
|
||||
PRINT_ERROR("scst_acg_remove_dev() returned %d", rc);
|
||||
res = rc;
|
||||
goto out_free_up;
|
||||
}
|
||||
break;
|
||||
case SCST_PROC_ACTION_CLEAR:
|
||||
list_for_each_entry_safe(acg_dev, acg_dev_tmp,
|
||||
&acg->acg_dev_list,
|
||||
acg_dev_list_entry) {
|
||||
rc = scst_acg_remove_dev(acg, acg_dev->dev);
|
||||
rc = scst_acg_remove_dev(acg, acg_dev->dev,
|
||||
list_is_last(&acg_dev->acg_dev_list_entry,
|
||||
&acg->acg_dev_list));
|
||||
if (rc) {
|
||||
PRINT_ERROR("scst_acg_remove_dev() "
|
||||
"return %d", rc);
|
||||
res = rc;
|
||||
goto out_free_up;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user