diff --git a/scst/include/scst.h b/scst/include/scst.h index 31e78d323..85b0f0aee 100644 --- a/scst/include/scst.h +++ b/scst/include/scst.h @@ -5430,6 +5430,8 @@ void scst_reassign_retained_sess_states(struct scst_session *new_sess, int scst_get_max_lun_commands(struct scst_session *sess, uint64_t lun); +void scst_dev_inquiry_data_changed(struct scst_device *dev); + /* * Has to be put here open coded, because Linux doesn't have equivalent, which * allows exclusive wake ups of threads in LIFO order. We need it to let (yet) diff --git a/scst/src/dev_handlers/scst_vdisk.c b/scst/src/dev_handlers/scst_vdisk.c index 0898a9490..a4d286259 100644 --- a/scst/src/dev_handlers/scst_vdisk.c +++ b/scst/src/dev_handlers/scst_vdisk.c @@ -244,6 +244,8 @@ struct scst_vdisk_dev { char *dif_filename; + struct work_struct vdev_inq_changed_work; + /* Only to pass it to attach() callback. Don't use them anywhere else! */ int blk_shift; enum scst_dif_mode dif_mode; @@ -663,7 +665,10 @@ static const struct attribute *vcdrom_attrs[] = { #endif /* CONFIG_SCST_PROC */ -/* Protects vdisks addition/deletion and related activities, like search */ +/* + * Protects vdisks addition/deletion and related activities, like search. + * Outer mutex regarding scst_mutex. + */ static DEFINE_MUTEX(scst_vdisk_mutex); /* @@ -7670,6 +7675,23 @@ static void vdisk_free_bioset(struct scst_vdisk_dev *virt_dev) } #endif +static void vdev_inq_changed_fn(struct work_struct *work) +{ + struct scst_vdisk_dev *virt_dev = container_of(work, + struct scst_vdisk_dev, vdev_inq_changed_work); + struct scst_device *dev = virt_dev->dev; + + TRACE_ENTRY(); + + TRACE_DBG("Updating INQUIRY data for virt_dev %p (dev %s)", + virt_dev, dev->virt_name); + + scst_dev_inquiry_data_changed(dev); + + TRACE_EXIT(); + return; +} + /* scst_vdisk_mutex supposed to be held */ static int vdev_create(struct scst_dev_type *devt, const char *name, struct scst_vdisk_dev **res_virt_dev) @@ -7703,6 +7725,7 @@ static int vdev_create(struct scst_dev_type *devt, virt_dev->thin_provisioned = DEF_THIN_PROVISIONED; virt_dev->tst = DEF_TST; virt_dev->expl_alua = DEF_EXPL_ALUA; + INIT_WORK(&virt_dev->vdev_inq_changed_work, vdev_inq_changed_fn); virt_dev->blk_shift = DEF_DISK_BLOCK_SHIFT; @@ -7764,6 +7787,8 @@ out_free: static void vdev_destroy(struct scst_vdisk_dev *virt_dev) { + cancel_work_sync(&virt_dev->vdev_inq_changed_work); + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30) vdisk_free_bioset(virt_dev); #endif @@ -9303,6 +9328,8 @@ static ssize_t vdev_sysfs_t10_vend_id_store(struct kobject *kobj, virt_dev->t10_vend_id_set = 1; write_unlock(&vdisk_serial_rwlock); + schedule_work(&virt_dev->vdev_inq_changed_work); + res = count; out: @@ -9362,6 +9389,8 @@ static ssize_t vdev_sysfs_vend_specific_id_store(struct kobject *kobj, virt_dev->vend_specific_id_set = 1; write_unlock(&vdisk_serial_rwlock); + schedule_work(&virt_dev->vdev_inq_changed_work); + res = count; out: @@ -9420,6 +9449,8 @@ static ssize_t vdev_sysfs_prod_id_store(struct kobject *kobj, virt_dev->prod_id_set = 1; write_unlock(&vdisk_serial_rwlock); + schedule_work(&virt_dev->vdev_inq_changed_work); + res = count; out: @@ -9478,6 +9509,8 @@ static ssize_t vdev_sysfs_prod_rev_lvl_store(struct kobject *kobj, virt_dev->prod_rev_lvl_set = 1; write_unlock(&vdisk_serial_rwlock); + schedule_work(&virt_dev->vdev_inq_changed_work); + res = count; out: @@ -9539,6 +9572,8 @@ static ssize_t vdev_sysfs_scsi_device_name_store(struct kobject *kobj, virt_dev->scsi_device_name_set = 0; write_unlock(&vdisk_serial_rwlock); + schedule_work(&virt_dev->vdev_inq_changed_work); + res = count; out: @@ -9609,6 +9644,8 @@ static ssize_t vdev_sysfs_t10_dev_id_store(struct kobject *kobj, virt_dev->t10_dev_id_set = 1; + schedule_work(&virt_dev->vdev_inq_changed_work); + res = count; PRINT_INFO("T10 device id for device %s changed to %s", virt_dev->name, @@ -9691,6 +9728,9 @@ static ssize_t vdev_sysfs_eui64_id_store(struct kobject *kobj, #endif write_unlock(&vdisk_serial_rwlock); + if (res >= 0) + schedule_work(&virt_dev->vdev_inq_changed_work); + out: return res; } @@ -9772,6 +9812,9 @@ static ssize_t vdev_sysfs_naa_id_store(struct kobject *kobj, #endif write_unlock(&vdisk_serial_rwlock); + if (res >= 0) + schedule_work(&virt_dev->vdev_inq_changed_work); + out: return res; } @@ -9835,6 +9878,8 @@ static ssize_t vdev_sysfs_usn_store(struct kobject *kobj, virt_dev->usn_set = 1; + schedule_work(&virt_dev->vdev_inq_changed_work); + res = count; PRINT_INFO("USN for device %s changed to %s", virt_dev->name, @@ -9889,6 +9934,8 @@ static ssize_t vdev_sysfs_inq_vend_specific_store(struct kobject *kobj, virt_dev->inq_vend_specific_len = len; write_unlock(&vdisk_serial_rwlock); + schedule_work(&virt_dev->vdev_inq_changed_work); + res = count; out: diff --git a/scst/src/scst_copy_mgr.c b/scst/src/scst_copy_mgr.c index 62fdb781a..f367da21f 100644 --- a/scst/src/scst_copy_mgr.c +++ b/scst/src/scst_copy_mgr.c @@ -2518,6 +2518,36 @@ static bool scst_cm_is_lun_free(unsigned int lun) return res; } +/* scst_mutex supposed to be held and activities suspended */ +static unsigned int scst_cm_get_lun(const struct scst_device *dev) +{ + unsigned int res = -1; + int i; + bool found = false; + + TRACE_ENTRY(); + + for (i = 0; i < SESS_TGT_DEV_LIST_HASH_SIZE; i++) { + struct list_head *head = &scst_cm_sess->sess_tgt_dev_list[i]; + struct scst_tgt_dev *tgt_dev; + list_for_each_entry(tgt_dev, head, sess_tgt_dev_list_entry) { + if (tgt_dev->dev == dev) { + res = tgt_dev->lun; + found = true; + TRACE_DBG("LUN %d found (full LUN %lld)", + res, tgt_dev->lun); + goto out; + } + } + } + + sBUG_ON(!found); + +out: + TRACE_EXIT_RES(res); + return res; +} + /* scst_mutex supposed to be held and activities suspended */ static int scst_cm_dev_register(struct scst_device *dev, uint64_t lun) { @@ -2583,6 +2613,7 @@ out_unblock: spin_lock_bh(&dev->dev_lock); scst_unblock_dev(dev); spin_unlock_bh(&dev->dev_lock); + scst_acg_del_lun(scst_cm_tgt->default_acg, lun, false); out_err: @@ -2629,6 +2660,41 @@ out: return; } +void scst_cm_update_dev(struct scst_device *dev) +{ + int rc; + + TRACE_ENTRY(); + + TRACE_MGMT_DBG("copy manager: updating device %s", dev->virt_name); + + scst_suspend_activity(SCST_SUSPEND_TIMEOUT_UNLIMITED); + mutex_lock(&scst_mutex); + + scst_cm_dev_unregister(dev, false); + + spin_lock_bh(&dev->dev_lock); + scst_block_dev(dev); + spin_unlock_bh(&dev->dev_lock); + + rc = scst_cm_send_init_inquiry(dev, scst_cm_get_lun(dev), NULL); + if (rc != 0) + goto out_unblock; + +out_resume: + mutex_unlock(&scst_mutex); + scst_resume_activity(); + + TRACE_EXIT(); + return; + +out_unblock: + spin_lock_bh(&dev->dev_lock); + scst_unblock_dev(dev); + spin_unlock_bh(&dev->dev_lock); + goto out_resume; +} + /* scst_mutex supposed to be held and activities suspended */ int scst_cm_on_dev_register(struct scst_device *dev) { @@ -3650,7 +3716,8 @@ static void scst_cm_task_mgmt_fn_done(struct scst_mgmt_cmd *scst_mcmd) static int scst_cm_report_aen(struct scst_aen *aen) { /* Nothing to do */ - return 0; + scst_aen_done(aen); + return SCST_AEN_RES_SUCCESS; } static struct scst_tgt_template scst_cm_tgtt = { diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index 67ae0de29..b0ce5f2e0 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -2855,6 +2855,30 @@ void scst_requeue_ua(struct scst_cmd *cmd, const uint8_t *buf, int size) return; } +void scst_dev_inquiry_data_changed(struct scst_device *dev) +{ + struct scst_tgt_dev *tgt_dev; + + TRACE_ENTRY(); + + TRACE_MGMT_DBG("Updating INQUIRY data for dev %s", dev->virt_name); + + mutex_lock(&scst_mutex); + + list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list, dev_tgt_dev_list_entry) { + TRACE_DBG("INQUIRY DATA HAS CHANGED on tgt_dev %p", tgt_dev); + scst_gen_aen_or_ua(tgt_dev, SCST_LOAD_SENSE(scst_sense_inquiry_data_changed)); + } + + mutex_unlock(&scst_mutex); + + scst_cm_update_dev(dev); + + TRACE_EXIT(); + return; +} +EXPORT_SYMBOL(scst_dev_inquiry_data_changed); + /* The activity supposed to be suspended and scst_mutex held */ static void scst_check_reassign_sess(struct scst_session *sess) { diff --git a/scst/src/scst_priv.h b/scst/src/scst_priv.h index 694d9e395..77711de83 100644 --- a/scst/src/scst_priv.h +++ b/scst/src/scst_priv.h @@ -862,6 +862,7 @@ static inline bool scst_lba1_inside_lba2(int64_t lba1, #ifndef CONFIG_SCST_PROC +void scst_cm_update_dev(struct scst_device *dev); int scst_cm_on_dev_register(struct scst_device *dev); void scst_cm_on_dev_unregister(struct scst_device *dev); @@ -895,6 +896,7 @@ void scst_cm_exit(void); #else /* #ifndef CONFIG_SCST_PROC */ +static inline void scst_cm_update_dev(struct scst_device *dev) {} static inline int scst_cm_on_dev_register(struct scst_device *dev) { return 0; } static inline void scst_cm_on_dev_unregister(struct scst_device *dev) {}