mirror of
https://github.com/SCST-project/scst.git
synced 2026-05-14 09:11:27 +00:00
- Support for Async. Event Notifications added
- Implemented "plug-and-play" notifications about new devices in security groups and changed size of a device both through AENs and Unit Attentions - New command SCST_USER_DEVICE_CAPACITY_CHANGED added to scst_user interface to notify SCST core that the corresponding device has changed its capacity - New command "resync_size" added to scst_vdisk proc interface to tell scst_vdisk to reread size of the corresponding device. - Docs update - Minor fixes and cleanups git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@697 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
@@ -576,6 +576,9 @@ subdirectories "vdisk" and "vcdrom". They have similar layout:
|
||||
|
||||
* "close NAME" - closes device "NAME".
|
||||
|
||||
* "resync_size NAME" - refreshes size of device "NAME". Intended to be
|
||||
used after device resize.
|
||||
|
||||
* "change NAME [PATH]" - changes a virtual CD in the VDISK CDROM.
|
||||
|
||||
By default, if neither BLOCKIO, nor NULLIO option is supplied, FILEIO
|
||||
|
||||
@@ -515,6 +515,9 @@ subdirectories "vdisk" and "vcdrom". They have similar layout:
|
||||
|
||||
* "close NAME" - closes device "NAME".
|
||||
|
||||
* "resync_size NAME" - refreshes size of device "NAME". Intended to be
|
||||
used after device resize.
|
||||
|
||||
* "change NAME [PATH]" - changes a virtual CD in the VDISK CDROM.
|
||||
|
||||
By default, if neither BLOCKIO, nor NULLIO option is supplied, FILEIO
|
||||
|
||||
@@ -269,8 +269,36 @@ enum scst_exec_context {
|
||||
#define SCST_PREPROCESS_STATUS_NEED_THREAD 4
|
||||
|
||||
/*************************************************************
|
||||
** Allowed return codes for xmit_response(), rdy_to_xfer(),
|
||||
** report_aen()
|
||||
** Values for AEN functions
|
||||
*************************************************************/
|
||||
|
||||
/*
|
||||
* SCSI Asynchronous Event. Parameter contains SCSI sense
|
||||
* (Unit Attention). AENs generated only for 2 the following UAs:
|
||||
* CAPACITY DATA HAS CHANGED and REPORTED LUNS DATA HAS CHANGED.
|
||||
* Other UAs reported regularly as CHECK CONDITION status,
|
||||
* because it doesn't look safe to report them using AENs, since
|
||||
* reporting using AENs opens delivery race windows even in case of
|
||||
* untagged commands.
|
||||
*/
|
||||
#define SCST_AEN_SCSI 0
|
||||
|
||||
/*************************************************************
|
||||
** Allowed return/status codes for report_aen() callback and
|
||||
** scst_set_aen_delivery_status() function
|
||||
*************************************************************/
|
||||
|
||||
/* Success */
|
||||
#define SCST_AEN_RES_SUCCESS 0
|
||||
|
||||
/* Not supported */
|
||||
#define SCST_AEN_RES_NOT_SUPPORTED -1
|
||||
|
||||
/* Failure */
|
||||
#define SCST_AEN_RES_FAILED -2
|
||||
|
||||
/*************************************************************
|
||||
** Allowed return codes for xmit_response(), rdy_to_xfer()
|
||||
*************************************************************/
|
||||
|
||||
/* Success */
|
||||
@@ -408,6 +436,21 @@ enum scst_exec_context {
|
||||
(__flags), NULL, NULL)
|
||||
#endif
|
||||
|
||||
/*************************************************************
|
||||
** Vlaid_mask constants for scst_analyze_sense()
|
||||
*************************************************************/
|
||||
|
||||
#define SCST_SENSE_KEY_VALID 1
|
||||
#define SCST_SENSE_ASC_VALID 2
|
||||
#define SCST_SENSE_ASCQ_VALID 4
|
||||
|
||||
#define SCST_SENSE_ASCx_VALID (SCST_SENSE_ASC_VALID | \
|
||||
SCST_SENSE_ASCQ_VALID)
|
||||
|
||||
#define SCST_SENSE_ALL_VALID (SCST_SENSE_KEY_VALID | \
|
||||
SCST_SENSE_ASC_VALID | \
|
||||
SCST_SENSE_ASCQ_VALID)
|
||||
|
||||
/*************************************************************
|
||||
* TYPES
|
||||
*************************************************************/
|
||||
@@ -422,6 +465,7 @@ struct scst_dev_type;
|
||||
struct scst_acg;
|
||||
struct scst_acg_dev;
|
||||
struct scst_acn;
|
||||
struct scst_aen;
|
||||
|
||||
/*
|
||||
* SCST uses 64-bit numbers to represent LUN's internally. The value
|
||||
@@ -665,17 +709,17 @@ struct scst_tgt_template {
|
||||
int (*release) (struct scst_tgt *tgt);
|
||||
|
||||
/*
|
||||
* This function is used for Asynchronous Event Notification.
|
||||
* It is the responsibility of the driver to notify any/all
|
||||
* initiators about the Asynchronous Event reported.
|
||||
* Returns one of the SCST_TGT_RES_* constants.
|
||||
* This function is used for Asynchronous Event Notifications.
|
||||
*
|
||||
* Returns one of the SCST_AEN_RES_* constants.
|
||||
* After AEN is sent, target driver must call scst_aen_done() and,
|
||||
* optionally, scst_set_aen_delivery_status().
|
||||
*
|
||||
* This command is expected to be NON-BLOCKING, but can sleep.
|
||||
*
|
||||
* MUST HAVE if low-level protocol supports AEN
|
||||
*
|
||||
* ToDo
|
||||
* MUST HAVE, if low-level protocol supports AENs.
|
||||
*/
|
||||
int (*report_aen) (int mgmt_fn, const uint8_t *lun, int lun_len);
|
||||
int (*report_aen) (struct scst_aen *aen);
|
||||
|
||||
/*
|
||||
* Those functions can be used to export the driver's statistics and
|
||||
@@ -1598,10 +1642,33 @@ struct scst_acn {
|
||||
struct scst_tgt_dev_UA {
|
||||
/* List entry in tgt_dev->UA_list */
|
||||
struct list_head UA_list_entry;
|
||||
|
||||
/* Set if UA is global for session */
|
||||
unsigned int global_UA:1;
|
||||
|
||||
/* Unit Attention sense */
|
||||
uint8_t UA_sense_buffer[SCST_SENSE_BUFFERSIZE];
|
||||
};
|
||||
|
||||
/* Used to deliver AENs */
|
||||
struct scst_aen {
|
||||
int event_fn; /* AEN fn */
|
||||
|
||||
struct scst_session *sess; /* corresponding session */
|
||||
uint64_t lun; /* corresponding LUN in SCSI form */
|
||||
|
||||
union {
|
||||
/* SCSI AEN data */
|
||||
struct {
|
||||
int aen_sense_len;
|
||||
uint8_t aen_sense[SCST_STANDARD_SENSE_LEN];
|
||||
};
|
||||
};
|
||||
|
||||
/* Keeps status of AEN's delivery to remote initiator */
|
||||
int delivery_status;
|
||||
};
|
||||
|
||||
#ifndef smp_mb__after_set_bit
|
||||
/* There is no smp_mb__after_set_bit() in the kernel */
|
||||
#define smp_mb__after_set_bit() smp_mb()
|
||||
@@ -1922,6 +1989,11 @@ void scst_set_busy(struct scst_cmd *cmd);
|
||||
*/
|
||||
void scst_set_initial_UA(struct scst_session *sess, int key, int asc, int ascq);
|
||||
|
||||
/*
|
||||
* Notifies SCST core that dev changed its capacity
|
||||
*/
|
||||
void scst_capacity_data_changed(struct scst_device *dev);
|
||||
|
||||
/*
|
||||
* Finds a command based on the supplied tag comparing it with one
|
||||
* that previously set by scst_cmd_set_tag().
|
||||
@@ -2340,8 +2412,8 @@ static inline void scst_clear_may_need_dma_sync(struct scst_cmd *cmd)
|
||||
}
|
||||
|
||||
/*
|
||||
* Get/clear functions for cmd's delivery_status. It is one of
|
||||
* SCST_CMD_DELIVERY_* constants, it specifies the status of the
|
||||
* Get/set functions for cmd's delivery_status. It is one of
|
||||
* SCST_CMD_DELIVERY_* constants. It specifies the status of the
|
||||
* command's delivery to initiator.
|
||||
*/
|
||||
static inline int scst_get_delivery_status(struct scst_cmd *cmd)
|
||||
@@ -2393,6 +2465,60 @@ void scst_prepare_async_mcmd(struct scst_mgmt_cmd *mcmd);
|
||||
*/
|
||||
void scst_async_mcmd_completed(struct scst_mgmt_cmd *mcmd, int status);
|
||||
|
||||
/* Returns AEN's fn */
|
||||
static inline int scst_aen_get_event_fn(struct scst_aen *aen)
|
||||
{
|
||||
return aen->event_fn;
|
||||
}
|
||||
|
||||
/* Returns AEN's session */
|
||||
static inline struct scst_session *scst_aen_get_sess(struct scst_aen *aen)
|
||||
{
|
||||
return aen->sess;
|
||||
}
|
||||
|
||||
/* Returns AEN's LUN */
|
||||
static inline uint64_t scst_aen_get_lun(struct scst_aen *aen)
|
||||
{
|
||||
return aen->lun;
|
||||
}
|
||||
|
||||
/* Returns SCSI AEN's sense */
|
||||
static inline const uint8_t *scst_aen_get_sense(struct scst_aen *aen)
|
||||
{
|
||||
return aen->aen_sense;
|
||||
}
|
||||
|
||||
/* Returns SCSI AEN's sense length */
|
||||
static inline int scst_aen_get_sense_len(struct scst_aen *aen)
|
||||
{
|
||||
return aen->aen_sense_len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get/set functions for AEN's delivery_status. It is one of
|
||||
* SCST_AEN_RES_* constants. It specifies the status of the
|
||||
* command's delivery to initiator.
|
||||
*/
|
||||
static inline int scst_get_aen_delivery_status(struct scst_aen *aen)
|
||||
{
|
||||
return aen->delivery_status;
|
||||
}
|
||||
|
||||
static inline void scst_set_aen_delivery_status(struct scst_aen *aen,
|
||||
int status)
|
||||
{
|
||||
aen->delivery_status = status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Notifies SCST that the driver has sent the AEN and it
|
||||
* can be freed now. Don't forget to set the delivery status, if it
|
||||
* isn't success, using scst_set_aen_delivery_status() before calling
|
||||
* this function.
|
||||
*/
|
||||
void scst_aen_done(struct scst_aen *aen);
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
|
||||
|
||||
static inline struct page *sg_page(struct scatterlist *sg)
|
||||
@@ -2410,6 +2536,13 @@ static inline void sg_init_table(struct scatterlist *sgl, unsigned int nents)
|
||||
memset(sgl, 0, sizeof(*sgl) * nents);
|
||||
}
|
||||
|
||||
static inline void sg_init_one(struct scatterlist *sg, const void *buf,
|
||||
unsigned int buflen)
|
||||
{
|
||||
sg_init_table(sg, 1);
|
||||
sg_set_buf(sg, buf, buflen);
|
||||
}
|
||||
|
||||
static inline void sg_assign_page(struct scatterlist *sg, struct page *page)
|
||||
{
|
||||
sg->page = page;
|
||||
@@ -2612,8 +2745,15 @@ int scst_alloc_sense(struct scst_cmd *cmd, int atomic);
|
||||
int scst_alloc_set_sense(struct scst_cmd *cmd, int atomic,
|
||||
const uint8_t *sense, unsigned int len);
|
||||
|
||||
void scst_set_sense(uint8_t *buffer, int len, int key,
|
||||
int asc, int ascq);
|
||||
void scst_set_sense(uint8_t *buffer, int len, int key, int asc, int ascq);
|
||||
|
||||
/*
|
||||
* Returnes true if sense matches to (key, asc, ascq) and false otherwise.
|
||||
* Valid_mask is one or several SCST_SENSE_*_VALID constants setting valid
|
||||
* (key, asc, ascq) values.
|
||||
*/
|
||||
bool scst_analyze_sense(const uint8_t *sense, int len, unsigned int valid_mask,
|
||||
int key, int asc, int ascq);
|
||||
|
||||
/*
|
||||
* Returnes a pseudo-random number for debugging purposes. Available only in
|
||||
|
||||
@@ -29,6 +29,12 @@
|
||||
/* Max size of CDB */
|
||||
#define SCST_MAX_CDB_SIZE 16
|
||||
|
||||
/*
|
||||
* Size of sense sufficient to carry standard sense data.
|
||||
* Warning! It's allocated on stack!
|
||||
*/
|
||||
#define SCST_STANDARD_SENSE_LEN 17
|
||||
|
||||
/* Max size of sense */
|
||||
#define SCST_SENSE_BUFFERSIZE 96
|
||||
|
||||
@@ -156,8 +162,8 @@ static inline int scst_is_ua_sense(const uint8_t *sense)
|
||||
#define scst_sense_not_ready NOT_READY, 0x04, 0x10
|
||||
#define scst_sense_invalid_message ILLEGAL_REQUEST, 0x49, 0
|
||||
#define scst_sense_cleared_by_another_ini_UA UNIT_ATTENTION, 0x2F, 0
|
||||
|
||||
#define SCST_STANDARD_SENSE_LEN 14
|
||||
#define scst_sense_capacity_data_changed UNIT_ATTENTION, 0x2A, 0x9
|
||||
#define scst_sense_reported_luns_data_changed UNIT_ATTENTION, 0x3F, 0xE
|
||||
|
||||
/*************************************************************
|
||||
* SCSI opcodes not listed anywhere else
|
||||
|
||||
@@ -242,6 +242,7 @@ struct scst_user_reply_cmd {
|
||||
#define SCST_USER_REPLY_AND_GET_CMD _IOWR('u', 5, struct scst_user_get_cmd)
|
||||
#define SCST_USER_REPLY_CMD _IOW('u', 6, struct scst_user_reply_cmd)
|
||||
#define SCST_USER_FLUSH_CACHE _IO('u', 7)
|
||||
#define SCST_USER_DEVICE_CAPACITY_CHANGED _IO('u', 8)
|
||||
|
||||
/* Values for scst_user_get_cmd.subcode */
|
||||
#define SCST_USER_ATTACH_SESS \
|
||||
|
||||
@@ -68,9 +68,8 @@ static int cdrom_attach(struct scst_device *dev)
|
||||
const int buffer_size = 512;
|
||||
uint8_t *buffer = NULL;
|
||||
int retries;
|
||||
unsigned char sense_buffer[SCST_SENSE_BUFFERSIZE];
|
||||
unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE];
|
||||
enum dma_data_direction data_dir;
|
||||
unsigned char *sbuff;
|
||||
struct cdrom_params *params;
|
||||
|
||||
TRACE_ENTRY();
|
||||
@@ -106,16 +105,15 @@ static int cdrom_attach(struct scst_device *dev)
|
||||
while (1) {
|
||||
memset(buffer, 0, buffer_size);
|
||||
data_dir = SCST_DATA_READ;
|
||||
sbuff = sense_buffer;
|
||||
|
||||
TRACE_DBG("%s", "Doing READ_CAPACITY");
|
||||
res = scsi_execute(dev->scsi_dev, cmd, data_dir, buffer,
|
||||
buffer_size, sbuff,
|
||||
buffer_size, sense_buffer,
|
||||
SCST_GENERIC_CDROM_REG_TIMEOUT, 3, 0);
|
||||
|
||||
TRACE_DBG("READ_CAPACITY done: %x", res);
|
||||
|
||||
if ((res == 0) || (sbuff[2] != UNIT_ATTENTION))
|
||||
if ((res == 0) || (sense_buffer[2] != UNIT_ATTENTION))
|
||||
break;
|
||||
|
||||
if (!--retries) {
|
||||
@@ -137,7 +135,7 @@ static int cdrom_attach(struct scst_device *dev)
|
||||
TRACE_DBG("Sector size is %i scsi_level %d(SCSI_2 %d)",
|
||||
sector_size, dev->scsi_dev->scsi_level, SCSI_2);
|
||||
} else {
|
||||
TRACE_BUFFER("Sense set", sbuff, SCST_SENSE_BUFFERSIZE);
|
||||
TRACE_BUFFER("Sense set", sense_buffer, sizeof(sense_buffer));
|
||||
params->block_shift = CDROM_DEF_BLOCK_SHIFT;
|
||||
}
|
||||
|
||||
|
||||
@@ -144,9 +144,8 @@ static int disk_attach(struct scst_device *dev)
|
||||
const int buffer_size = 512;
|
||||
uint8_t *buffer = NULL;
|
||||
int retries;
|
||||
unsigned char sense_buffer[SCST_SENSE_BUFFERSIZE];
|
||||
unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE];
|
||||
enum dma_data_direction data_dir;
|
||||
unsigned char *sbuff;
|
||||
struct disk_params *params;
|
||||
|
||||
TRACE_ENTRY();
|
||||
@@ -182,16 +181,16 @@ static int disk_attach(struct scst_device *dev)
|
||||
while (1) {
|
||||
memset(buffer, 0, buffer_size);
|
||||
data_dir = SCST_DATA_READ;
|
||||
sbuff = sense_buffer;
|
||||
|
||||
TRACE_DBG("%s", "Doing READ_CAPACITY");
|
||||
res = scsi_execute(dev->scsi_dev, cmd, data_dir, buffer,
|
||||
buffer_size, sbuff,
|
||||
buffer_size, sense_buffer,
|
||||
SCST_GENERIC_DISK_REG_TIMEOUT, 3, 0);
|
||||
|
||||
TRACE_DBG("READ_CAPACITY done: %x", res);
|
||||
|
||||
if (!res || (sbuff[12] != 0x28 && sbuff[12] != 0x29))
|
||||
if (!res || (sense_buffer[12] != 0x28 &&
|
||||
sense_buffer[12] != 0x29))
|
||||
break;
|
||||
if (!--retries) {
|
||||
PRINT_ERROR("UA not clear after %d retries",
|
||||
@@ -209,7 +208,7 @@ static int disk_attach(struct scst_device *dev)
|
||||
params->block_shift =
|
||||
scst_calc_block_shift(sector_size);
|
||||
} else {
|
||||
TRACE_BUFFER("Sense set", sbuff, SCST_SENSE_BUFFERSIZE);
|
||||
TRACE_BUFFER("Sense set", sense_buffer, sizeof(sense_buffer));
|
||||
res = -ENODEV;
|
||||
goto out_free_buf;
|
||||
}
|
||||
|
||||
@@ -144,9 +144,8 @@ static int modisk_attach(struct scst_device *dev)
|
||||
const int buffer_size = 512;
|
||||
uint8_t *buffer = NULL;
|
||||
int retries;
|
||||
unsigned char sense_buffer[SCST_SENSE_BUFFERSIZE];
|
||||
unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE];
|
||||
enum dma_data_direction data_dir;
|
||||
unsigned char *sbuff;
|
||||
struct modisk_params *params;
|
||||
|
||||
TRACE_ENTRY();
|
||||
@@ -196,16 +195,15 @@ static int modisk_attach(struct scst_device *dev)
|
||||
while (1) {
|
||||
memset(buffer, 0, buffer_size);
|
||||
data_dir = SCST_DATA_READ;
|
||||
sbuff = sense_buffer;
|
||||
|
||||
TRACE_DBG("%s", "Doing READ_CAPACITY");
|
||||
res = scsi_execute(dev->scsi_dev, cmd, data_dir, buffer,
|
||||
buffer_size, sbuff,
|
||||
buffer_size, sense_buffer,
|
||||
SCST_GENERIC_MODISK_REG_TIMEOUT, 3, 0);
|
||||
|
||||
TRACE_DBG("READ_CAPACITY done: %x", res);
|
||||
|
||||
if (!res || (sbuff[2] != UNIT_ATTENTION))
|
||||
if (!res || (sense_buffer[2] != UNIT_ATTENTION))
|
||||
break;
|
||||
|
||||
if (!--retries) {
|
||||
@@ -226,9 +224,9 @@ static int modisk_attach(struct scst_device *dev)
|
||||
TRACE_DBG("Sector size is %i scsi_level %d(SCSI_2 %d)",
|
||||
sector_size, dev->scsi_dev->scsi_level, SCSI_2);
|
||||
} else {
|
||||
TRACE_BUFFER("Sense set", sbuff, SCST_SENSE_BUFFERSIZE);
|
||||
TRACE_BUFFER("Sense set", sense_buffer, sizeof(sense_buffer));
|
||||
|
||||
if (sbuff[2] != NOT_READY) {
|
||||
if (sense_buffer[2] != NOT_READY) {
|
||||
res = -ENODEV;
|
||||
goto out_free_buf;
|
||||
}
|
||||
|
||||
@@ -336,7 +336,17 @@ static int tape_done(struct scst_cmd *cmd)
|
||||
else if ((status == SAM_STAT_CHECK_CONDITION) &&
|
||||
SCST_SENSE_VALID(cmd->sense)) {
|
||||
struct tape_params *params;
|
||||
TRACE_DBG("%s", "Extended sense");
|
||||
|
||||
TRACE_DBG("Extended sense %x", cmd->sense[0] & 0x7F);
|
||||
|
||||
if ((cmd->sense[0] & 0x7F) != 0x70) {
|
||||
PRINT_ERROR("Sense format 0x%x is not supported",
|
||||
cmd->sense[0] & 0x7F);
|
||||
scst_set_cmd_error(cmd,
|
||||
SCST_LOAD_SENSE(scst_sense_hardw_error));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (opcode == READ_6 && !(cmd->cdb[1] & SILI_BIT) &&
|
||||
(cmd->sense[2] & 0xe0)) {
|
||||
/* EOF, EOM, or ILI */
|
||||
@@ -374,6 +384,7 @@ static int tape_done(struct scst_cmd *cmd)
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
TRACE_DBG("cmd->is_send_status=%x, cmd->resp_data_len=%d, "
|
||||
"res=%d", cmd->is_send_status, cmd->resp_data_len, res);
|
||||
|
||||
|
||||
@@ -186,6 +186,7 @@ static int dev_user_register_dev(struct file *file,
|
||||
const struct scst_user_dev_desc *dev_desc);
|
||||
static int dev_user_unregister_dev(struct file *file);
|
||||
static int dev_user_flush_cache(struct file *file);
|
||||
static int dev_user_capacity_changed(struct file *file);
|
||||
static int __dev_user_set_opt(struct scst_user_dev *dev,
|
||||
const struct scst_user_opt *opt);
|
||||
static int dev_user_set_opt(struct file *file, const struct scst_user_opt *opt);
|
||||
@@ -1862,6 +1863,11 @@ static long dev_user_ioctl(struct file *file, unsigned int cmd,
|
||||
res = dev_user_get_opt(file, (void __user *)arg);
|
||||
break;
|
||||
|
||||
case SCST_USER_DEVICE_CAPACITY_CHANGED:
|
||||
TRACE_DBG("%s", "CAPACITY_CHANGED");
|
||||
res = dev_user_capacity_changed(file);
|
||||
break;
|
||||
|
||||
default:
|
||||
PRINT_ERROR("Invalid ioctl cmd %x", cmd);
|
||||
res = -EINVAL;
|
||||
@@ -2765,6 +2771,33 @@ out:
|
||||
return res;
|
||||
}
|
||||
|
||||
static int dev_user_capacity_changed(struct file *file)
|
||||
{
|
||||
int res;
|
||||
struct scst_user_dev *dev;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
mutex_lock(&dev_priv_mutex);
|
||||
dev = (struct scst_user_dev *)file->private_data;
|
||||
res = dev_user_check_reg(dev);
|
||||
if (res != 0) {
|
||||
mutex_unlock(&dev_priv_mutex);
|
||||
goto out;
|
||||
}
|
||||
down_read(&dev->dev_rwsem);
|
||||
mutex_unlock(&dev_priv_mutex);
|
||||
|
||||
scst_capacity_data_changed(dev->sdev);
|
||||
|
||||
up_read(&dev->dev_rwsem);
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static int __dev_user_set_opt(struct scst_user_dev *dev,
|
||||
const struct scst_user_opt *opt)
|
||||
{
|
||||
|
||||
@@ -93,6 +93,8 @@ static struct scst_proc_log vdisk_proc_local_trace_tbl[] =
|
||||
#define VDISK_NAME "vdisk"
|
||||
#define VCDROM_NAME "vcdrom"
|
||||
|
||||
#define VDISK_NULLIO_SIZE 3LL*1024*1024*1024*1024/2
|
||||
|
||||
#define DEF_TST SCST_CONTR_MODE_SEP_TASK_SETS
|
||||
/*
|
||||
* Since we can't control backstorage device's reordering, we have to always
|
||||
@@ -361,9 +363,9 @@ static struct scst_dev_type vcdrom_devtype = VCDROM_TYPE;
|
||||
static struct scst_vdisk_thr nullio_thr_data;
|
||||
|
||||
static char *vdisk_proc_help_string =
|
||||
"echo \"open|close NAME [FILE_NAME [BLOCK_SIZE] [WRITE_THROUGH "
|
||||
"READ_ONLY O_DIRECT NULLIO NV_CACHE BLOCKIO]]\" >/proc/scsi_tgt/"
|
||||
VDISK_NAME "/" VDISK_NAME "\n";
|
||||
"echo \"open|close|resync_size NAME [FILE_NAME [BLOCK_SIZE] "
|
||||
"[WRITE_THROUGH READ_ONLY O_DIRECT NULLIO NV_CACHE BLOCKIO]]\" "
|
||||
">/proc/scsi_tgt/" VDISK_NAME "/" VDISK_NAME "\n";
|
||||
|
||||
static char *vcdrom_proc_help_string =
|
||||
"echo \"open|change|close NAME [FILE_NAME]\" "
|
||||
@@ -407,6 +409,76 @@ static struct file *vdisk_open(const struct scst_vdisk_dev *virt_dev)
|
||||
return fd;
|
||||
}
|
||||
|
||||
/**************************************************************
|
||||
* Function: vdisk_get_file_size
|
||||
*
|
||||
* Argument:
|
||||
*
|
||||
* Returns : 0 on success and file size in *file_size,
|
||||
* error code otherwise
|
||||
*
|
||||
* Description:
|
||||
*************************************************************/
|
||||
static int vdisk_get_check_file_size(const char *file_name, bool blockio,
|
||||
loff_t *file_size)
|
||||
{
|
||||
struct inode *inode;
|
||||
int res = 0;
|
||||
struct file *fd;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
*file_size = 0;
|
||||
|
||||
fd = filp_open(file_name, O_LARGEFILE | O_RDONLY, 0600);
|
||||
if (IS_ERR(fd)) {
|
||||
res = PTR_ERR(fd);
|
||||
PRINT_ERROR("filp_open(%s) returned error %d", file_name, res);
|
||||
goto out;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
|
||||
if ((fd->f_op == NULL) ||
|
||||
(fd->f_op->readv == NULL) ||
|
||||
(fd->f_op->writev == NULL)) {
|
||||
#else
|
||||
if ((fd->f_op == NULL) ||
|
||||
(fd->f_op->aio_read == NULL) ||
|
||||
(fd->f_op->aio_write == NULL)) {
|
||||
#endif
|
||||
PRINT_ERROR("%s", "Wrong f_op or FS doesn't have required "
|
||||
"capabilities");
|
||||
res = -EINVAL;
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
inode = fd->f_dentry->d_inode;
|
||||
|
||||
if (blockio && !S_ISBLK(inode->i_mode)) {
|
||||
PRINT_ERROR("File %s is NOT a block device", file_name);
|
||||
res = -EINVAL;
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
if (S_ISREG(inode->i_mode))
|
||||
/* Nothing to do*/;
|
||||
else if (S_ISBLK(inode->i_mode))
|
||||
inode = inode->i_bdev->bd_inode;
|
||||
else {
|
||||
res = -EINVAL;
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
*file_size = inode->i_size;
|
||||
|
||||
out_close:
|
||||
filp_close(fd, NULL);
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
/**************************************************************
|
||||
* Function: vdisk_attach
|
||||
*
|
||||
@@ -420,7 +492,6 @@ static int vdisk_attach(struct scst_device *dev)
|
||||
{
|
||||
int res = 0;
|
||||
loff_t err;
|
||||
struct file *fd;
|
||||
struct scst_vdisk_dev *virt_dev = NULL, *vv;
|
||||
struct list_head *vd;
|
||||
|
||||
@@ -462,56 +533,12 @@ static int vdisk_attach(struct scst_device *dev)
|
||||
|
||||
if (!virt_dev->cdrom_empty) {
|
||||
if (virt_dev->nullio)
|
||||
err = 3LL*1024*1024*1024*1024/2;
|
||||
err = VDISK_NULLIO_SIZE;
|
||||
else {
|
||||
struct inode *inode;
|
||||
|
||||
fd = vdisk_open(virt_dev);
|
||||
if (IS_ERR(fd)) {
|
||||
res = PTR_ERR(fd);
|
||||
PRINT_ERROR("filp_open(%s) returned error %d",
|
||||
virt_dev->file_name, res);
|
||||
res = vdisk_get_check_file_size(virt_dev->file_name,
|
||||
virt_dev->blockio, &err);
|
||||
if (res != 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
|
||||
if ((fd->f_op == NULL) ||
|
||||
(fd->f_op->readv == NULL) ||
|
||||
(fd->f_op->writev == NULL)) {
|
||||
#else
|
||||
if ((fd->f_op == NULL) ||
|
||||
(fd->f_op->aio_read == NULL) ||
|
||||
(fd->f_op->aio_write == NULL)) {
|
||||
#endif
|
||||
PRINT_ERROR("%s", "Wrong f_op or FS doesn't "
|
||||
"have required capabilities");
|
||||
res = -EINVAL;
|
||||
filp_close(fd, NULL);
|
||||
goto out;
|
||||
}
|
||||
|
||||
inode = fd->f_dentry->d_inode;
|
||||
|
||||
if (virt_dev->blockio && !S_ISBLK(inode->i_mode)) {
|
||||
PRINT_ERROR("File %s is NOT a block device",
|
||||
virt_dev->file_name);
|
||||
res = -EINVAL;
|
||||
filp_close(fd, NULL);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (S_ISREG(inode->i_mode))
|
||||
/* Nothing to do*/;
|
||||
else if (S_ISBLK(inode->i_mode))
|
||||
inode = inode->i_bdev->bd_inode;
|
||||
else {
|
||||
res = -EINVAL;
|
||||
filp_close(fd, NULL);
|
||||
goto out;
|
||||
}
|
||||
err = inode->i_size;
|
||||
|
||||
filp_close(fd, NULL);
|
||||
}
|
||||
virt_dev->file_size = err;
|
||||
TRACE_DBG("size of file: %lld", (long long unsigned int)err);
|
||||
@@ -2777,6 +2804,46 @@ static void vdisk_report_registering(const char *type,
|
||||
return;
|
||||
}
|
||||
|
||||
/* scst_vdisk_mutex supposed to be held */
|
||||
static int vdisk_resync_size(struct scst_vdisk_dev *virt_dev)
|
||||
{
|
||||
loff_t err;
|
||||
int res = 0;
|
||||
|
||||
if (!virt_dev->nullio) {
|
||||
res = vdisk_get_check_file_size(virt_dev->file_name,
|
||||
virt_dev->blockio, &err);
|
||||
if (res != 0)
|
||||
goto out;
|
||||
} else
|
||||
err = VDISK_NULLIO_SIZE;
|
||||
|
||||
res = scst_suspend_activity(true);
|
||||
if (res != 0)
|
||||
goto out;
|
||||
|
||||
virt_dev->file_size = err;
|
||||
virt_dev->nblocks = virt_dev->file_size >> virt_dev->block_shift;
|
||||
|
||||
scst_dev_del_all_thr_data(virt_dev->dev);
|
||||
|
||||
PRINT_INFO("New size of SCSI target virtual disk %s "
|
||||
"(fs=%lldMB, bs=%d, nblocks=%lld, cyln=%lld%s)",
|
||||
virt_dev->name, virt_dev->file_size >> 20,
|
||||
virt_dev->block_size,
|
||||
(long long unsigned int)virt_dev->nblocks,
|
||||
(long long unsigned int)virt_dev->nblocks/64/32,
|
||||
virt_dev->nblocks < 64*32 ? " !WARNING! cyln less "
|
||||
"than 1" : "");
|
||||
|
||||
scst_capacity_data_changed(virt_dev->dev);
|
||||
|
||||
scst_resume_activity();
|
||||
|
||||
out:
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when a file in the /proc/VDISK_NAME/VDISK_NAME is written
|
||||
*/
|
||||
@@ -2810,6 +2877,9 @@ static int vdisk_write_proc(char *buffer, char **start, off_t offset,
|
||||
action = 0;
|
||||
} else if (!strncmp("open ", p, 5)) {
|
||||
p += 5;
|
||||
action = 1;
|
||||
} else if (!strncmp("resync_size ", p, 12)) {
|
||||
p += 12;
|
||||
action = 2;
|
||||
} else {
|
||||
PRINT_ERROR("Unknown action \"%s\"", p);
|
||||
@@ -2834,12 +2904,11 @@ static int vdisk_write_proc(char *buffer, char **start, off_t offset,
|
||||
goto out_up;
|
||||
}
|
||||
|
||||
if (action) {
|
||||
if (action == 1) {
|
||||
/* open */
|
||||
virt_dev = NULL;
|
||||
list_for_each_entry(vv, &vdisk_dev_list,
|
||||
vdisk_dev_list_entry)
|
||||
{
|
||||
vdisk_dev_list_entry) {
|
||||
if (strcmp(vv->name, name) == 0) {
|
||||
virt_dev = vv;
|
||||
break;
|
||||
@@ -2992,11 +3061,10 @@ static int vdisk_write_proc(char *buffer, char **start, off_t offset,
|
||||
"vdisk_dev_list", virt_dev->name,
|
||||
virt_dev->file_name, virt_dev->virt_id,
|
||||
virt_dev->block_size);
|
||||
} else { /* close */
|
||||
} else if (action == 0) { /* close */
|
||||
virt_dev = NULL;
|
||||
list_for_each_entry(vv, &vdisk_dev_list,
|
||||
vdisk_dev_list_entry)
|
||||
{
|
||||
vdisk_dev_list_entry) {
|
||||
if (strcmp(vv->name, name) == 0) {
|
||||
virt_dev = vv;
|
||||
break;
|
||||
@@ -3016,6 +3084,24 @@ static int vdisk_write_proc(char *buffer, char **start, off_t offset,
|
||||
|
||||
kfree(virt_dev->file_name);
|
||||
kfree(virt_dev);
|
||||
} else { /* resync_size */
|
||||
virt_dev = NULL;
|
||||
list_for_each_entry(vv, &vdisk_dev_list,
|
||||
vdisk_dev_list_entry) {
|
||||
if (strcmp(vv->name, name) == 0) {
|
||||
virt_dev = vv;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (virt_dev == NULL) {
|
||||
PRINT_ERROR("Device %s not found", name);
|
||||
res = -EINVAL;
|
||||
goto out_up;
|
||||
}
|
||||
|
||||
res = vdisk_resync_size(virt_dev);
|
||||
if (res != 0)
|
||||
goto out_up;
|
||||
}
|
||||
res = length;
|
||||
|
||||
@@ -3169,9 +3255,7 @@ out:
|
||||
/* scst_vdisk_mutex supposed to be held */
|
||||
static int vcdrom_change(char *p, char *name)
|
||||
{
|
||||
struct file *fd;
|
||||
loff_t err;
|
||||
mm_segment_t old_fs;
|
||||
struct scst_vdisk_dev *virt_dev, *vv;
|
||||
char *file_name, *fn, *old_fn;
|
||||
int len;
|
||||
@@ -3179,8 +3263,7 @@ static int vcdrom_change(char *p, char *name)
|
||||
|
||||
virt_dev = NULL;
|
||||
list_for_each_entry(vv, &vcdrom_dev_list,
|
||||
vdisk_dev_list_entry)
|
||||
{
|
||||
vdisk_dev_list_entry) {
|
||||
if (strcmp(vv->name, name) == 0) {
|
||||
virt_dev = vv;
|
||||
break;
|
||||
@@ -3225,45 +3308,17 @@ static int vcdrom_change(char *p, char *name)
|
||||
strncpy(fn, file_name, len);
|
||||
virt_dev->file_name = fn;
|
||||
|
||||
fd = vdisk_open(virt_dev);
|
||||
if (IS_ERR(fd)) {
|
||||
res = PTR_ERR(fd);
|
||||
PRINT_ERROR("filp_open(%s) returned an error %d",
|
||||
virt_dev->file_name, res);
|
||||
res = vdisk_get_check_file_size(virt_dev->file_name,
|
||||
virt_dev->blockio, &err);
|
||||
if (res != 0)
|
||||
goto out_free;
|
||||
}
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
|
||||
if ((fd->f_op == NULL) || (fd->f_op->readv == NULL)) {
|
||||
#else
|
||||
if ((fd->f_op == NULL) || (fd->f_op->aio_read == NULL)) {
|
||||
#endif
|
||||
PRINT_ERROR("%s", "Wrong f_op or FS doesn't "
|
||||
"have required capabilities");
|
||||
res = -EINVAL;
|
||||
filp_close(fd, NULL);
|
||||
goto out_free;
|
||||
}
|
||||
/* seek to end */
|
||||
old_fs = get_fs();
|
||||
set_fs(get_ds());
|
||||
if (fd->f_op->llseek)
|
||||
err = fd->f_op->llseek(fd, 0, 2/*SEEK_END*/);
|
||||
else
|
||||
err = default_llseek(fd, 0, 2/*SEEK_END*/);
|
||||
set_fs(old_fs);
|
||||
filp_close(fd, NULL);
|
||||
if (err < 0) {
|
||||
res = err;
|
||||
PRINT_ERROR("llseek %s returned an error %d",
|
||||
virt_dev->file_name, res);
|
||||
goto out_free;
|
||||
}
|
||||
} else {
|
||||
len = 0;
|
||||
err = 0;
|
||||
fn = NULL;
|
||||
virt_dev->file_name = fn;
|
||||
virt_dev->file_name = NULL;
|
||||
}
|
||||
|
||||
if (virt_dev->nullio)
|
||||
err = VDISK_NULLIO_SIZE;
|
||||
|
||||
res = scst_suspend_activity(true);
|
||||
if (res != 0)
|
||||
|
||||
@@ -37,8 +37,10 @@
|
||||
static void scst_free_tgt_dev(struct scst_tgt_dev *tgt_dev);
|
||||
static void scst_check_internal_sense(struct scst_device *dev, int result,
|
||||
uint8_t *sense, int sense_len);
|
||||
static void __scst_check_set_UA(struct scst_tgt_dev *tgt_dev,
|
||||
const uint8_t *sense, int sense_len, int flags);
|
||||
static void scst_alloc_set_UA(struct scst_tgt_dev *tgt_dev,
|
||||
const uint8_t *sense, int sense_len, int head);
|
||||
const uint8_t *sense, int sense_len, int flags);
|
||||
static void scst_free_all_UA(struct scst_tgt_dev *tgt_dev);
|
||||
static void scst_release_space(struct scst_cmd *cmd);
|
||||
static void scst_sess_free_tgt_devs(struct scst_session *sess);
|
||||
@@ -61,7 +63,8 @@ int scst_alloc_sense(struct scst_cmd *cmd, int atomic)
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
sBUG_ON(cmd->sense != NULL);
|
||||
if (cmd->sense != NULL)
|
||||
goto memzero;
|
||||
|
||||
cmd->sense = mempool_alloc(scst_sense_mempool, gfp_mask);
|
||||
if (cmd->sense == NULL) {
|
||||
@@ -71,6 +74,7 @@ int scst_alloc_sense(struct scst_cmd *cmd, int atomic)
|
||||
goto out;
|
||||
}
|
||||
|
||||
memzero:
|
||||
memset(cmd->sense, 0, SCST_SENSE_BUFFERSIZE);
|
||||
|
||||
out:
|
||||
@@ -146,20 +150,55 @@ out:
|
||||
}
|
||||
EXPORT_SYMBOL(scst_set_cmd_error);
|
||||
|
||||
void scst_set_sense(uint8_t *buffer, int len, int key,
|
||||
int asc, int ascq)
|
||||
void scst_set_sense(uint8_t *buffer, int len, int key, int asc, int ascq)
|
||||
{
|
||||
sBUG_ON(len < SCST_STANDARD_SENSE_LEN);
|
||||
|
||||
memset(buffer, 0, len);
|
||||
|
||||
buffer[0] = 0x70; /* Error Code */
|
||||
buffer[2] = key; /* Sense Key */
|
||||
buffer[7] = 0x0a; /* Additional Sense Length */
|
||||
buffer[12] = asc; /* ASC */
|
||||
buffer[13] = ascq; /* ASCQ */
|
||||
|
||||
TRACE_BUFFER("Sense set", buffer, len);
|
||||
return;
|
||||
}
|
||||
EXPORT_SYMBOL(scst_set_sense);
|
||||
|
||||
bool scst_analyze_sense(const uint8_t *sense, int len, unsigned int valid_mask,
|
||||
int key, int asc, int ascq)
|
||||
{
|
||||
bool res = false;
|
||||
|
||||
if (len < 14)
|
||||
goto out;
|
||||
|
||||
/* Error Code */
|
||||
if (sense[0] != 0x70)
|
||||
goto out;
|
||||
|
||||
/* Sense Key */
|
||||
if ((valid_mask & SCST_SENSE_KEY_VALID) && (sense[2] != key))
|
||||
goto out;
|
||||
|
||||
/* ASC */
|
||||
if ((valid_mask & SCST_SENSE_ASC_VALID) && (sense[12] != asc))
|
||||
goto out;
|
||||
|
||||
/* ASCQ */
|
||||
if ((valid_mask & SCST_SENSE_ASCQ_VALID) && (sense[13] != ascq))
|
||||
goto out;
|
||||
|
||||
res = true;
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES((int)res);
|
||||
return res;
|
||||
}
|
||||
EXPORT_SYMBOL(scst_analyze_sense);
|
||||
|
||||
static void scst_set_cmd_error_sense(struct scst_cmd *cmd, uint8_t *sense,
|
||||
unsigned int len)
|
||||
{
|
||||
@@ -207,7 +246,7 @@ void scst_set_initial_UA(struct scst_session *sess, int key, int asc, int ascq)
|
||||
asc, ascq);
|
||||
|
||||
/* Protect sess_tgt_dev_list_hash */
|
||||
mutex_lock(&scst_mutex);
|
||||
mutex_lock(&scst_mutex);
|
||||
|
||||
for (i = 0; i < TGT_DEV_HASH_SIZE; i++) {
|
||||
struct list_head *sess_tgt_dev_list_head =
|
||||
@@ -219,15 +258,14 @@ void scst_set_initial_UA(struct scst_session *sess, int key, int asc, int ascq)
|
||||
spin_lock_bh(&tgt_dev->tgt_dev_lock);
|
||||
if (!list_empty(&tgt_dev->UA_list)) {
|
||||
struct scst_tgt_dev_UA *ua;
|
||||
uint8_t *sense;
|
||||
|
||||
ua = list_entry(tgt_dev->UA_list.next,
|
||||
typeof(*ua), UA_list_entry);
|
||||
sense = ua->UA_sense_buffer;
|
||||
if ((sense[2] == UNIT_ATTENTION) &&
|
||||
(sense[12] == 0x29) &&
|
||||
(sense[13] == 0)) {
|
||||
scst_set_sense(sense,
|
||||
if (scst_analyze_sense(ua->UA_sense_buffer,
|
||||
sizeof(ua->UA_sense_buffer),
|
||||
SCST_SENSE_ALL_VALID,
|
||||
SCST_LOAD_SENSE(scst_sense_reset_UA))) {
|
||||
scst_set_sense(ua->UA_sense_buffer,
|
||||
sizeof(ua->UA_sense_buffer),
|
||||
key, asc, ascq);
|
||||
} else
|
||||
@@ -240,13 +278,307 @@ void scst_set_initial_UA(struct scst_session *sess, int key, int asc, int ascq)
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&scst_mutex);
|
||||
mutex_unlock(&scst_mutex);
|
||||
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
}
|
||||
EXPORT_SYMBOL(scst_set_initial_UA);
|
||||
|
||||
static struct scst_aen *scst_alloc_aen(struct scst_tgt_dev *tgt_dev)
|
||||
{
|
||||
struct scst_aen *aen;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
aen = mempool_alloc(scst_aen_mempool, GFP_KERNEL);
|
||||
if (aen == NULL) {
|
||||
PRINT_ERROR("AEN memory allocation failed. Corresponding "
|
||||
"event notification will not be performed (initiator "
|
||||
"%s)", tgt_dev->sess->initiator_name);
|
||||
goto out;
|
||||
}
|
||||
memset(aen, 0, sizeof(*aen));
|
||||
|
||||
aen->sess = tgt_dev->sess;
|
||||
scst_sess_get(aen->sess);
|
||||
|
||||
aen->lun = scst_pack_lun(tgt_dev->lun);
|
||||
|
||||
out:
|
||||
TRACE_EXIT_HRES((unsigned long)aen);
|
||||
return aen;
|
||||
};
|
||||
|
||||
static void scst_free_aen(struct scst_aen *aen)
|
||||
{
|
||||
TRACE_ENTRY();
|
||||
|
||||
scst_sess_put(aen->sess);
|
||||
mempool_free(aen, scst_aen_mempool);
|
||||
|
||||
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();
|
||||
|
||||
if (dev->type != TYPE_DISK) {
|
||||
TRACE_MGMT_DBG("Device type %d isn't for CAPACITY DATA "
|
||||
"CHANGED UA", dev->type);
|
||||
goto out;
|
||||
}
|
||||
|
||||
TRACE_MGMT_DBG("CAPACITY DATA CHANGED (dev %p)", dev);
|
||||
|
||||
scst_set_sense(sense_buffer, sizeof(sense_buffer),
|
||||
SCST_LOAD_SENSE(scst_sense_capacity_data_changed));
|
||||
|
||||
mutex_lock(&scst_mutex);
|
||||
|
||||
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,
|
||||
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_check_set_UA(tgt_dev, sense_buffer,
|
||||
sizeof(sense_buffer), 0);
|
||||
}
|
||||
|
||||
mutex_unlock(&scst_mutex);
|
||||
|
||||
out:
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
}
|
||||
EXPORT_SYMBOL(scst_capacity_data_changed);
|
||||
|
||||
static inline bool scst_is_report_luns_changed_type(int type)
|
||||
{
|
||||
switch (type) {
|
||||
case TYPE_DISK:
|
||||
case TYPE_TAPE:
|
||||
case TYPE_PRINTER:
|
||||
case TYPE_PROCESSOR:
|
||||
case TYPE_WORM:
|
||||
case TYPE_ROM:
|
||||
case TYPE_SCANNER:
|
||||
case TYPE_MOD:
|
||||
case TYPE_MEDIUM_CHANGER:
|
||||
case TYPE_RAID:
|
||||
case TYPE_ENCLOSURE:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* scst_mutex supposed to be held */
|
||||
void scst_queue_report_luns_changed_UA(struct scst_session *sess, int flags)
|
||||
{
|
||||
uint8_t sense_buffer[SCST_STANDARD_SENSE_LEN];
|
||||
struct list_head *shead;
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
int i;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
scst_set_sense(sense_buffer, sizeof(sense_buffer),
|
||||
SCST_LOAD_SENSE(scst_sense_reported_luns_data_changed));
|
||||
|
||||
TRACE_MGMT_DBG("Queuing REPORTED LUNS DATA CHANGED UA "
|
||||
"(sess %p)", sess);
|
||||
|
||||
for (i = 0; i < TGT_DEV_HASH_SIZE; i++) {
|
||||
shead = &sess->sess_tgt_dev_list_hash[i];
|
||||
|
||||
list_for_each_entry(tgt_dev, shead,
|
||||
sess_tgt_dev_list_entry) {
|
||||
spin_lock_bh(&tgt_dev->tgt_dev_lock);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < TGT_DEV_HASH_SIZE; i++) {
|
||||
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))
|
||||
continue;
|
||||
|
||||
__scst_check_set_UA(tgt_dev, sense_buffer,
|
||||
sizeof(sense_buffer),
|
||||
flags | SCST_SET_UA_FLAG_GLOBAL);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = TGT_DEV_HASH_SIZE-1; i >= 0; i--) {
|
||||
shead = &sess->sess_tgt_dev_list_hash[i];
|
||||
|
||||
list_for_each_entry_reverse(tgt_dev,
|
||||
shead, sess_tgt_dev_list_entry) {
|
||||
spin_unlock_bh(&tgt_dev->tgt_dev_lock);
|
||||
}
|
||||
}
|
||||
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
}
|
||||
|
||||
/* The activity supposed to be suspended and scst_mutex held */
|
||||
void scst_report_luns_changed(struct scst_acg *acg)
|
||||
{
|
||||
struct scst_session *sess;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
TRACE_MGMT_DBG("REPORTED LUNS DATA CHANGED (acg %s)", acg->acg_name);
|
||||
|
||||
list_for_each_entry(sess, &acg->acg_sess_list, acg_sess_list_entry) {
|
||||
int i;
|
||||
struct list_head *shead;
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
struct scst_tgt_template *tgtt = sess->tgt->tgtt;
|
||||
|
||||
for (i = 0; i < TGT_DEV_HASH_SIZE; i++) {
|
||||
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))
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
TRACE_MGMT_DBG("Not found a device capable REPORTED "
|
||||
"LUNS DATA CHANGED UA (sess %p)", sess);
|
||||
continue;
|
||||
found:
|
||||
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,
|
||||
SCST_LOAD_SENSE(scst_sense_reported_luns_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:
|
||||
scst_queue_report_luns_changed_UA(sess, 0);
|
||||
}
|
||||
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
}
|
||||
|
||||
void scst_aen_done(struct scst_aen *aen)
|
||||
{
|
||||
TRACE_ENTRY();
|
||||
|
||||
TRACE_MGMT_DBG("AEN %p (fn %d) done (initiator %s)", aen,
|
||||
aen->event_fn, aen->sess->initiator_name);
|
||||
|
||||
if (aen->delivery_status == SCST_AEN_RES_SUCCESS)
|
||||
goto out_free;
|
||||
|
||||
if (aen->event_fn != SCST_AEN_SCSI)
|
||||
goto out_free;
|
||||
|
||||
TRACE_MGMT_DBG("Delivery of SCSI AEN failed (initiator %s)",
|
||||
aen->sess->initiator_name);
|
||||
|
||||
if (scst_analyze_sense(aen->aen_sense, aen->aen_sense_len,
|
||||
SCST_SENSE_ALL_VALID,
|
||||
SCST_LOAD_SENSE(
|
||||
scst_sense_reported_luns_data_changed))) {
|
||||
mutex_lock(&scst_mutex);
|
||||
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 */
|
||||
struct list_head *shead;
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
uint64_t lun;
|
||||
|
||||
lun = scst_unpack_lun((uint8_t *)&aen->lun, sizeof(aen->lun));
|
||||
|
||||
mutex_lock(&scst_mutex);
|
||||
|
||||
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);
|
||||
scst_check_set_UA(tgt_dev, aen->aen_sense,
|
||||
aen->aen_sense_len,
|
||||
SCST_SET_UA_FLAG_AT_HEAD);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&scst_mutex);
|
||||
} else
|
||||
PRINT_ERROR("%s", "Unknown SCSI AEN");
|
||||
|
||||
out_free:
|
||||
scst_free_aen(aen);
|
||||
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
}
|
||||
EXPORT_SYMBOL(scst_aen_done);
|
||||
|
||||
int scst_get_cmd_abnormal_done_state(const struct scst_cmd *cmd)
|
||||
{
|
||||
int res;
|
||||
@@ -274,12 +606,15 @@ int scst_get_cmd_abnormal_done_state(const struct scst_cmd *cmd)
|
||||
res = SCST_CMD_STATE_XMIT_RESP;
|
||||
break;
|
||||
|
||||
case SCST_CMD_STATE_PREPROCESS_DONE:
|
||||
case SCST_CMD_STATE_PREPARE_SPACE:
|
||||
case SCST_CMD_STATE_RDY_TO_XFER:
|
||||
case SCST_CMD_STATE_DATA_WAIT:
|
||||
case SCST_CMD_STATE_TGT_PRE_EXEC:
|
||||
case SCST_CMD_STATE_SEND_FOR_EXEC:
|
||||
case SCST_CMD_STATE_LOCAL_EXEC:
|
||||
case SCST_CMD_STATE_REAL_EXEC:
|
||||
case SCST_CMD_STATE_REAL_EXECUTING:
|
||||
res = SCST_CMD_STATE_PRE_DEV_DONE;
|
||||
break;
|
||||
|
||||
@@ -559,6 +894,7 @@ static struct scst_tgt_dev *scst_alloc_add_tgt_dev(struct scst_session *sess,
|
||||
struct list_head *sess_tgt_dev_list_head;
|
||||
struct scst_tgt_template *vtt = sess->tgt->tgtt;
|
||||
int rc, i;
|
||||
uint8_t sense_buffer[SCST_STANDARD_SENSE_LEN];
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
@@ -652,11 +988,9 @@ static struct scst_tgt_dev *scst_alloc_add_tgt_dev(struct scst_session *sess,
|
||||
&tgt_dev->tgt_dev_flags);
|
||||
}
|
||||
|
||||
spin_lock_bh(&scst_temp_UA_lock);
|
||||
scst_set_sense(scst_temp_UA, sizeof(scst_temp_UA),
|
||||
scst_set_sense(sense_buffer, sizeof(sense_buffer),
|
||||
SCST_LOAD_SENSE(scst_sense_reset_UA));
|
||||
scst_alloc_set_UA(tgt_dev, scst_temp_UA, sizeof(scst_temp_UA), 0);
|
||||
spin_unlock_bh(&scst_temp_UA_lock);
|
||||
scst_alloc_set_UA(tgt_dev, sense_buffer, sizeof(sense_buffer), 0);
|
||||
|
||||
tm_dbg_init_tgt_dev(tgt_dev, acg_dev);
|
||||
|
||||
@@ -726,11 +1060,11 @@ void scst_nexus_loss(struct scst_tgt_dev *tgt_dev, bool queue_UA)
|
||||
spin_unlock_bh(&tgt_dev->tgt_dev_lock);
|
||||
|
||||
if (queue_UA) {
|
||||
spin_lock_bh(&scst_temp_UA_lock);
|
||||
scst_set_sense(scst_temp_UA, sizeof(scst_temp_UA),
|
||||
uint8_t sense_buffer[SCST_STANDARD_SENSE_LEN];
|
||||
scst_set_sense(sense_buffer, sizeof(sense_buffer),
|
||||
SCST_LOAD_SENSE(scst_sense_nexus_loss_UA));
|
||||
scst_check_set_UA(tgt_dev, scst_temp_UA, sizeof(scst_temp_UA), 0);
|
||||
spin_unlock_bh(&scst_temp_UA_lock);
|
||||
scst_check_set_UA(tgt_dev, sense_buffer,
|
||||
sizeof(sense_buffer), 0);
|
||||
}
|
||||
|
||||
TRACE_EXIT();
|
||||
@@ -879,24 +1213,24 @@ int scst_acg_add_dev(struct scst_acg *acg, struct scst_device *dev,
|
||||
&tmp_tgt_dev_list);
|
||||
}
|
||||
|
||||
out:
|
||||
if (res == 0) {
|
||||
if (dev->virt_name != NULL) {
|
||||
PRINT_INFO("Added device %s to group %s (LUN %lld, "
|
||||
"rd_only %d)", dev->virt_name, acg->acg_name,
|
||||
(long long unsigned int)lun,
|
||||
read_only);
|
||||
} else {
|
||||
PRINT_INFO("Added device %d:%d:%d:%d to group %s (LUN "
|
||||
"%lld, rd_only %d)",
|
||||
dev->scsi_dev->host->host_no,
|
||||
dev->scsi_dev->channel, dev->scsi_dev->id,
|
||||
dev->scsi_dev->lun, acg->acg_name,
|
||||
(long long unsigned int)lun,
|
||||
read_only);
|
||||
}
|
||||
scst_report_luns_changed(acg);
|
||||
|
||||
if (dev->virt_name != NULL) {
|
||||
PRINT_INFO("Added device %s to group %s (LUN %lld, "
|
||||
"rd_only %d)", dev->virt_name, acg->acg_name,
|
||||
(long long unsigned int)lun,
|
||||
read_only);
|
||||
} else {
|
||||
PRINT_INFO("Added device %d:%d:%d:%d to group %s (LUN "
|
||||
"%lld, rd_only %d)",
|
||||
dev->scsi_dev->host->host_no,
|
||||
dev->scsi_dev->channel, dev->scsi_dev->id,
|
||||
dev->scsi_dev->lun, acg->acg_name,
|
||||
(long long unsigned int)lun,
|
||||
read_only);
|
||||
}
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
|
||||
@@ -938,19 +1272,19 @@ int scst_acg_remove_dev(struct scst_acg *acg, struct scst_device *dev)
|
||||
}
|
||||
scst_free_acg_dev(acg_dev);
|
||||
|
||||
out:
|
||||
if (res == 0) {
|
||||
if (dev->virt_name != NULL) {
|
||||
PRINT_INFO("Removed device %s from group %s",
|
||||
dev->virt_name, acg->acg_name);
|
||||
} else {
|
||||
PRINT_INFO("Removed device %d:%d:%d:%d from group %s",
|
||||
dev->scsi_dev->host->host_no,
|
||||
dev->scsi_dev->channel, dev->scsi_dev->id,
|
||||
dev->scsi_dev->lun, acg->acg_name);
|
||||
}
|
||||
scst_report_luns_changed(acg);
|
||||
|
||||
if (dev->virt_name != NULL) {
|
||||
PRINT_INFO("Removed device %s from group %s",
|
||||
dev->virt_name, acg->acg_name);
|
||||
} else {
|
||||
PRINT_INFO("Removed device %d:%d:%d:%d from group %s",
|
||||
dev->scsi_dev->host->host_no,
|
||||
dev->scsi_dev->channel, dev->scsi_dev->id,
|
||||
dev->scsi_dev->lun, acg->acg_name);
|
||||
}
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
@@ -1078,9 +1412,8 @@ out:
|
||||
int scst_prepare_request_sense(struct scst_cmd *orig_cmd)
|
||||
{
|
||||
int res = 0;
|
||||
#define sbuf_size 252
|
||||
static const uint8_t request_sense[6] =
|
||||
{ REQUEST_SENSE, 0, 0, 0, sbuf_size, 0 };
|
||||
{ REQUEST_SENSE, 0, 0, 0, SCST_SENSE_BUFFERSIZE, 0 };
|
||||
struct scst_cmd *rs_cmd;
|
||||
|
||||
TRACE_ENTRY();
|
||||
@@ -1092,7 +1425,8 @@ int scst_prepare_request_sense(struct scst_cmd *orig_cmd)
|
||||
orig_cmd->sense = NULL;
|
||||
}
|
||||
|
||||
rs_cmd = scst_create_prepare_internal_cmd(orig_cmd, sbuf_size);
|
||||
rs_cmd = scst_create_prepare_internal_cmd(orig_cmd,
|
||||
SCST_SENSE_BUFFERSIZE);
|
||||
if (rs_cmd == NULL)
|
||||
goto out_error;
|
||||
|
||||
@@ -1100,7 +1434,7 @@ int scst_prepare_request_sense(struct scst_cmd *orig_cmd)
|
||||
rs_cmd->cdb_len = sizeof(request_sense);
|
||||
rs_cmd->data_direction = SCST_DATA_READ;
|
||||
rs_cmd->expected_data_direction = rs_cmd->data_direction;
|
||||
rs_cmd->expected_transfer_len = sbuf_size;
|
||||
rs_cmd->expected_transfer_len = SCST_SENSE_BUFFERSIZE;
|
||||
rs_cmd->expected_values_set = 1;
|
||||
|
||||
TRACE(TRACE_MGMT_MINOR, "Adding REQUEST SENSE cmd %p to head of active "
|
||||
@@ -1117,7 +1451,6 @@ out:
|
||||
out_error:
|
||||
res = -1;
|
||||
goto out;
|
||||
#undef sbuf_size
|
||||
}
|
||||
|
||||
static void scst_complete_request_sense(struct scst_cmd *req_cmd)
|
||||
@@ -1246,7 +1579,7 @@ static void scst_send_release(struct scst_device *dev)
|
||||
{
|
||||
struct scsi_device *scsi_dev;
|
||||
unsigned char cdb[6];
|
||||
unsigned char *sense;
|
||||
uint8_t sense[SCSI_SENSE_BUFFERSIZE];
|
||||
int rc, i;
|
||||
|
||||
TRACE_ENTRY();
|
||||
@@ -1254,9 +1587,6 @@ static void scst_send_release(struct scst_device *dev)
|
||||
if (dev->scsi_dev == NULL)
|
||||
goto out;
|
||||
|
||||
/* We can't afford missing RELEASE due to memory shortage */
|
||||
sense = kmalloc(SCST_SENSE_BUFFERSIZE, GFP_KERNEL|__GFP_NOFAIL);
|
||||
|
||||
scsi_dev = dev->scsi_dev;
|
||||
|
||||
for (i = 0; i < 5; i++) {
|
||||
@@ -1265,7 +1595,7 @@ static void scst_send_release(struct scst_device *dev)
|
||||
cdb[1] = (scsi_dev->scsi_level <= SCSI_2) ?
|
||||
((scsi_dev->lun << 5) & 0xe0) : 0;
|
||||
|
||||
memset(sense, 0, SCST_SENSE_BUFFERSIZE);
|
||||
memset(sense, 0, sizeof(sense));
|
||||
|
||||
TRACE(TRACE_DEBUG | TRACE_SCSI, "%s", "Sending RELEASE req to "
|
||||
"SCSI mid-level");
|
||||
@@ -1277,15 +1607,12 @@ static void scst_send_release(struct scst_device *dev)
|
||||
break;
|
||||
} else {
|
||||
PRINT_ERROR("RELEASE failed: %d", rc);
|
||||
PRINT_BUFFER("RELEASE sense", sense,
|
||||
SCST_SENSE_BUFFERSIZE);
|
||||
scst_check_internal_sense(dev, rc,
|
||||
sense, SCST_SENSE_BUFFERSIZE);
|
||||
PRINT_BUFFER("RELEASE sense", sense, sizeof(sense));
|
||||
scst_check_internal_sense(dev, rc, sense,
|
||||
sizeof(sense));
|
||||
}
|
||||
}
|
||||
|
||||
kfree(sense);
|
||||
|
||||
out:
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
@@ -2117,6 +2444,19 @@ out:
|
||||
}
|
||||
EXPORT_SYMBOL(scst_get_cdb_info);
|
||||
|
||||
/* Packs SCST LUN back to SCSI form using peripheral device addressing method */
|
||||
uint64_t scst_pack_lun(const uint64_t lun)
|
||||
{
|
||||
uint64_t res;
|
||||
uint16_t *p = (uint16_t *)&res;
|
||||
|
||||
res = lun;
|
||||
*p = cpu_to_be16(*p);
|
||||
|
||||
TRACE_EXIT_HRES((unsigned long)res);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Routine to extract a lun number from an 8-byte LUN structure
|
||||
* in network byte order (BE).
|
||||
@@ -2670,7 +3010,7 @@ int scst_obtain_device_parameters(struct scst_device *dev)
|
||||
int res = 0, i;
|
||||
uint8_t cmd[16];
|
||||
uint8_t buffer[4+0x0A];
|
||||
uint8_t sense_buffer[SCST_SENSE_BUFFERSIZE];
|
||||
uint8_t sense_buffer[SCSI_SENSE_BUFFERSIZE];
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
@@ -2741,7 +3081,10 @@ int scst_obtain_device_parameters(struct scst_device *dev)
|
||||
if (
|
||||
#endif
|
||||
SCST_SENSE_VALID(sense_buffer)) {
|
||||
if (sense_buffer[2] == ILLEGAL_REQUEST) {
|
||||
if (scst_analyze_sense(sense_buffer,
|
||||
sizeof(sense_buffer),
|
||||
SCST_SENSE_KEY_VALID,
|
||||
ILLEGAL_REQUEST, 0, 0)) {
|
||||
TRACE(TRACE_SCSI|TRACE_MGMT_MINOR,
|
||||
"Device %d:%d:%d:%d doesn't"
|
||||
" support control mode page,"
|
||||
@@ -2759,7 +3102,10 @@ int scst_obtain_device_parameters(struct scst_device *dev)
|
||||
dev->has_own_order_mgmt);
|
||||
res = 0;
|
||||
goto out;
|
||||
} else if (sense_buffer[2] == NOT_READY) {
|
||||
} else if (scst_analyze_sense(sense_buffer,
|
||||
sizeof(sense_buffer),
|
||||
SCST_SENSE_KEY_VALID,
|
||||
NOT_READY, 0, 0)) {
|
||||
TRACE(TRACE_SCSI,
|
||||
"Device %d:%d:%d:%d not ready",
|
||||
dev->scsi_dev->host->host_no,
|
||||
@@ -2863,13 +3209,11 @@ void scst_process_reset(struct scst_device *dev,
|
||||
}
|
||||
|
||||
if (setUA) {
|
||||
/* BH already off */
|
||||
spin_lock(&scst_temp_UA_lock);
|
||||
scst_set_sense(scst_temp_UA, sizeof(scst_temp_UA),
|
||||
uint8_t sense_buffer[SCST_STANDARD_SENSE_LEN];
|
||||
scst_set_sense(sense_buffer, sizeof(sense_buffer),
|
||||
SCST_LOAD_SENSE(scst_sense_reset_UA));
|
||||
scst_dev_check_set_local_UA(dev, exclude_cmd, scst_temp_UA,
|
||||
sizeof(scst_temp_UA));
|
||||
spin_unlock(&scst_temp_UA_lock);
|
||||
scst_dev_check_set_local_UA(dev, exclude_cmd, sense_buffer,
|
||||
sizeof(sense_buffer));
|
||||
}
|
||||
|
||||
TRACE_EXIT();
|
||||
@@ -2878,8 +3222,10 @@ void scst_process_reset(struct scst_device *dev,
|
||||
|
||||
int scst_set_pending_UA(struct scst_cmd *cmd)
|
||||
{
|
||||
int res = 0;
|
||||
int res = 0, i;
|
||||
struct scst_tgt_dev_UA *UA_entry;
|
||||
bool first = true, global_unlock = false;
|
||||
struct scst_session *sess = cmd->sess;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
@@ -2887,6 +3233,7 @@ int scst_set_pending_UA(struct scst_cmd *cmd)
|
||||
|
||||
spin_lock_bh(&cmd->tgt_dev->tgt_dev_lock);
|
||||
|
||||
again:
|
||||
/* UA list could be cleared behind us, so retest */
|
||||
if (list_empty(&cmd->tgt_dev->UA_list)) {
|
||||
TRACE_DBG("%s",
|
||||
@@ -2901,6 +3248,28 @@ int scst_set_pending_UA(struct scst_cmd *cmd)
|
||||
TRACE_DBG("next %p UA_entry %p",
|
||||
cmd->tgt_dev->UA_list.next, UA_entry);
|
||||
|
||||
if (UA_entry->global_UA && first) {
|
||||
TRACE_MGMT_DBG("Global UA %p detected", UA_entry);
|
||||
|
||||
spin_unlock_bh(&cmd->tgt_dev->tgt_dev_lock);
|
||||
|
||||
mutex_lock(&scst_mutex);
|
||||
|
||||
for (i = 0; i < TGT_DEV_HASH_SIZE; i++) {
|
||||
struct list_head *sess_tgt_dev_list_head =
|
||||
&sess->sess_tgt_dev_list_hash[i];
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
list_for_each_entry(tgt_dev, sess_tgt_dev_list_head,
|
||||
sess_tgt_dev_list_entry) {
|
||||
spin_lock_bh(&tgt_dev->tgt_dev_lock);
|
||||
}
|
||||
}
|
||||
|
||||
first = false;
|
||||
global_unlock = true;
|
||||
goto again;
|
||||
}
|
||||
|
||||
scst_set_cmd_error_sense(cmd, UA_entry->UA_sense_buffer,
|
||||
sizeof(UA_entry->UA_sense_buffer));
|
||||
|
||||
@@ -2908,6 +3277,33 @@ int scst_set_pending_UA(struct scst_cmd *cmd)
|
||||
|
||||
list_del(&UA_entry->UA_list_entry);
|
||||
|
||||
if (UA_entry->global_UA) {
|
||||
for (i = 0; i < TGT_DEV_HASH_SIZE; i++) {
|
||||
struct list_head *sess_tgt_dev_list_head =
|
||||
&sess->sess_tgt_dev_list_hash[i];
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
|
||||
list_for_each_entry(tgt_dev, sess_tgt_dev_list_head,
|
||||
sess_tgt_dev_list_entry) {
|
||||
struct scst_tgt_dev_UA *ua;
|
||||
list_for_each_entry(ua, &tgt_dev->UA_list,
|
||||
UA_list_entry) {
|
||||
if (ua->global_UA &&
|
||||
memcmp(ua->UA_sense_buffer,
|
||||
UA_entry->UA_sense_buffer,
|
||||
sizeof(ua->UA_sense_buffer)) == 0) {
|
||||
TRACE_MGMT_DBG("Freeing not "
|
||||
"needed global UA %p",
|
||||
ua);
|
||||
list_del(&ua->UA_list_entry);
|
||||
mempool_free(ua, scst_ua_mempool);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mempool_free(UA_entry, scst_ua_mempool);
|
||||
|
||||
if (list_empty(&cmd->tgt_dev->UA_list)) {
|
||||
@@ -2915,20 +3311,32 @@ int scst_set_pending_UA(struct scst_cmd *cmd)
|
||||
&cmd->tgt_dev->tgt_dev_flags);
|
||||
}
|
||||
|
||||
out_unlock:
|
||||
if (global_unlock) {
|
||||
for (i = TGT_DEV_HASH_SIZE-1; i >= 0; i--) {
|
||||
struct list_head *sess_tgt_dev_list_head =
|
||||
&sess->sess_tgt_dev_list_hash[i];
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
list_for_each_entry_reverse(tgt_dev, sess_tgt_dev_list_head,
|
||||
sess_tgt_dev_list_entry) {
|
||||
spin_unlock_bh(&tgt_dev->tgt_dev_lock);
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&scst_mutex);
|
||||
|
||||
spin_lock_bh(&cmd->tgt_dev->tgt_dev_lock);
|
||||
}
|
||||
|
||||
spin_unlock_bh(&cmd->tgt_dev->tgt_dev_lock);
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
|
||||
out_unlock:
|
||||
spin_unlock_bh(&cmd->tgt_dev->tgt_dev_lock);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Called under tgt_dev_lock and BH off */
|
||||
static void scst_alloc_set_UA(struct scst_tgt_dev *tgt_dev,
|
||||
const uint8_t *sense, int sense_len, int head)
|
||||
const uint8_t *sense, int sense_len, int flags)
|
||||
{
|
||||
struct scst_tgt_dev_UA *UA_entry = NULL;
|
||||
|
||||
@@ -2944,6 +3352,10 @@ static void scst_alloc_set_UA(struct scst_tgt_dev *tgt_dev,
|
||||
}
|
||||
memset(UA_entry, 0, sizeof(*UA_entry));
|
||||
|
||||
UA_entry->global_UA = (flags & SCST_SET_UA_FLAG_GLOBAL) != 0;
|
||||
if (UA_entry->global_UA)
|
||||
TRACE_MGMT_DBG("Queuing global UA %p", UA_entry);
|
||||
|
||||
if (sense_len > (int)sizeof(UA_entry->UA_sense_buffer))
|
||||
sense_len = sizeof(UA_entry->UA_sense_buffer);
|
||||
memcpy(UA_entry->UA_sense_buffer, sense, sense_len);
|
||||
@@ -2952,7 +3364,7 @@ static void scst_alloc_set_UA(struct scst_tgt_dev *tgt_dev,
|
||||
|
||||
TRACE_MGMT_DBG("Adding new UA to tgt_dev %p", tgt_dev);
|
||||
|
||||
if (head)
|
||||
if (flags & SCST_SET_UA_FLAG_AT_HEAD)
|
||||
list_add(&UA_entry->UA_list_entry, &tgt_dev->UA_list);
|
||||
else
|
||||
list_add_tail(&UA_entry->UA_list_entry, &tgt_dev->UA_list);
|
||||
@@ -2962,20 +3374,19 @@ out:
|
||||
return;
|
||||
}
|
||||
|
||||
void scst_check_set_UA(struct scst_tgt_dev *tgt_dev,
|
||||
const uint8_t *sense, int sense_len, int head)
|
||||
/* tgt_dev_lock supposed to be held and BH off */
|
||||
static void __scst_check_set_UA(struct scst_tgt_dev *tgt_dev,
|
||||
const uint8_t *sense, int sense_len, int flags)
|
||||
{
|
||||
int skip_UA = 0;
|
||||
struct scst_tgt_dev_UA *UA_entry_tmp;
|
||||
int len = min((int)sizeof(UA_entry_tmp->UA_sense_buffer), sense_len);
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
spin_lock_bh(&tgt_dev->tgt_dev_lock);
|
||||
|
||||
list_for_each_entry(UA_entry_tmp, &tgt_dev->UA_list,
|
||||
UA_list_entry) {
|
||||
if (memcmp(sense, UA_entry_tmp->UA_sense_buffer,
|
||||
sense_len) == 0) {
|
||||
if (memcmp(sense, UA_entry_tmp->UA_sense_buffer, len) == 0) {
|
||||
TRACE_MGMT_DBG("%s", "UA already exists");
|
||||
skip_UA = 1;
|
||||
break;
|
||||
@@ -2983,8 +3394,19 @@ void scst_check_set_UA(struct scst_tgt_dev *tgt_dev,
|
||||
}
|
||||
|
||||
if (skip_UA == 0)
|
||||
scst_alloc_set_UA(tgt_dev, sense, sense_len, head);
|
||||
scst_alloc_set_UA(tgt_dev, sense, len, flags);
|
||||
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
}
|
||||
|
||||
void scst_check_set_UA(struct scst_tgt_dev *tgt_dev,
|
||||
const uint8_t *sense, int sense_len, int flags)
|
||||
{
|
||||
TRACE_ENTRY();
|
||||
|
||||
spin_lock_bh(&tgt_dev->tgt_dev_lock);
|
||||
__scst_check_set_UA(tgt_dev, sense, sense_len, flags);
|
||||
spin_unlock_bh(&tgt_dev->tgt_dev_lock);
|
||||
|
||||
TRACE_EXIT();
|
||||
@@ -3021,7 +3443,8 @@ void __scst_dev_check_set_UA(struct scst_device *dev,
|
||||
TRACE(TRACE_MGMT_MINOR, "Processing UA dev %p", dev);
|
||||
|
||||
/* Check for reset UA */
|
||||
if (sense[12] == SCST_SENSE_ASC_UA_RESET)
|
||||
if (scst_analyze_sense(sense, sense_len, SCST_SENSE_ASC_VALID,
|
||||
0, SCST_SENSE_ASC_UA_RESET, 0))
|
||||
scst_process_reset(dev,
|
||||
(exclude != NULL) ? exclude->sess : NULL,
|
||||
exclude, NULL, false);
|
||||
@@ -3044,7 +3467,7 @@ static void scst_free_all_UA(struct scst_tgt_dev *tgt_dev)
|
||||
TRACE_MGMT_DBG("Clearing UA for tgt_dev lun %lld",
|
||||
(long long unsigned int)tgt_dev->lun);
|
||||
list_del(&UA_entry->UA_list_entry);
|
||||
kfree(UA_entry);
|
||||
mempool_free(UA_entry, scst_ua_mempool);
|
||||
}
|
||||
INIT_LIST_HEAD(&tgt_dev->UA_list);
|
||||
clear_bit(SCST_TGT_DEV_UA_PENDING, &tgt_dev->tgt_dev_flags);
|
||||
|
||||
@@ -85,6 +85,8 @@ static struct kmem_cache *scst_ua_cachep;
|
||||
mempool_t *scst_ua_mempool;
|
||||
static struct kmem_cache *scst_sense_cachep;
|
||||
mempool_t *scst_sense_mempool;
|
||||
static struct kmem_cache *scst_aen_cachep;
|
||||
mempool_t *scst_aen_mempool;
|
||||
struct kmem_cache *scst_tgtd_cachep;
|
||||
struct kmem_cache *scst_sess_cachep;
|
||||
struct kmem_cache *scst_acgd_cachep;
|
||||
@@ -133,13 +135,6 @@ static int suspend_count;
|
||||
|
||||
static int scst_virt_dev_last_id; /* protected by scst_mutex */
|
||||
|
||||
/*
|
||||
* This buffer and lock are intended to avoid memory allocation, which
|
||||
* could fail in improper places.
|
||||
*/
|
||||
spinlock_t scst_temp_UA_lock;
|
||||
uint8_t scst_temp_UA[SCST_SENSE_BUFFERSIZE];
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
|
||||
#if defined(CONFIG_BLOCK) && defined(SCST_ALLOC_IO_CONTEXT_EXPORTED)
|
||||
static struct io_context *scst_ioc;
|
||||
@@ -1765,8 +1760,6 @@ static int __init init_scst(void)
|
||||
mutex_init(&scst_suspend_mutex);
|
||||
INIT_LIST_HEAD(&scst_cmd_lists_list);
|
||||
scst_virt_dev_last_id = 1;
|
||||
spin_lock_init(&scst_temp_UA_lock);
|
||||
|
||||
spin_lock_init(&scst_main_cmd_lists.cmd_list_lock);
|
||||
INIT_LIST_HEAD(&scst_main_cmd_lists.active_cmd_list);
|
||||
init_waitqueue_head(&scst_main_cmd_lists.cmd_list_waitQ);
|
||||
@@ -1807,7 +1800,8 @@ static int __init init_scst(void)
|
||||
INIT_CACHEP(scst_sense_cachep, scst_sense,
|
||||
out_destroy_ua_cache);
|
||||
}
|
||||
INIT_CACHEP(scst_cmd_cachep, scst_cmd, out_destroy_sense_cache);
|
||||
INIT_CACHEP(scst_aen_cachep, scst_aen, out_destroy_sense_cache);
|
||||
INIT_CACHEP(scst_cmd_cachep, scst_cmd, out_destroy_aen_cache);
|
||||
INIT_CACHEP(scst_sess_cachep, scst_session, out_destroy_cmd_cache);
|
||||
INIT_CACHEP(scst_tgtd_cachep, scst_tgt_dev, out_destroy_sess_cache);
|
||||
INIT_CACHEP(scst_acgd_cachep, scst_acg_dev, out_destroy_tgt_cache);
|
||||
@@ -1843,6 +1837,13 @@ static int __init init_scst(void)
|
||||
goto out_destroy_ua_mempool;
|
||||
}
|
||||
|
||||
scst_aen_mempool = mempool_create(100, mempool_alloc_slab,
|
||||
mempool_free_slab, scst_aen_cachep);
|
||||
if (scst_aen_mempool == NULL) {
|
||||
res = -ENOMEM;
|
||||
goto out_destroy_sense_mempool;
|
||||
}
|
||||
|
||||
if (scst_max_cmd_mem == 0) {
|
||||
struct sysinfo si;
|
||||
si_meminfo(&si);
|
||||
@@ -1870,7 +1871,7 @@ static int __init init_scst(void)
|
||||
res = scst_sgv_pools_init(
|
||||
((uint64_t)scst_max_cmd_mem << 10) >> (PAGE_SHIFT - 10), 0);
|
||||
if (res != 0)
|
||||
goto out_destroy_sense_mempool;
|
||||
goto out_destroy_aen_mempool;
|
||||
|
||||
scst_default_acg = scst_alloc_add_acg(SCST_DEFAULT_ACG_NAME);
|
||||
if (scst_default_acg == NULL) {
|
||||
@@ -1925,6 +1926,9 @@ out_free_acg:
|
||||
out_destroy_sgv_pool:
|
||||
scst_sgv_pools_deinit();
|
||||
|
||||
out_destroy_aen_mempool:
|
||||
mempool_destroy(scst_aen_mempool);
|
||||
|
||||
out_destroy_sense_mempool:
|
||||
mempool_destroy(scst_sense_mempool);
|
||||
|
||||
@@ -1949,6 +1953,9 @@ out_destroy_sess_cache:
|
||||
out_destroy_cmd_cache:
|
||||
kmem_cache_destroy(scst_cmd_cachep);
|
||||
|
||||
out_destroy_aen_cache:
|
||||
kmem_cache_destroy(scst_aen_cachep);
|
||||
|
||||
out_destroy_sense_cache:
|
||||
kmem_cache_destroy(scst_sense_cachep);
|
||||
|
||||
@@ -1987,11 +1994,13 @@ static void __exit exit_scst(void)
|
||||
mempool_destroy(scst_mgmt_stub_mempool);
|
||||
mempool_destroy(scst_ua_mempool);
|
||||
mempool_destroy(scst_sense_mempool);
|
||||
mempool_destroy(scst_aen_mempool);
|
||||
|
||||
DEINIT_CACHEP(scst_mgmt_cachep);
|
||||
DEINIT_CACHEP(scst_mgmt_stub_cachep);
|
||||
DEINIT_CACHEP(scst_ua_cachep);
|
||||
DEINIT_CACHEP(scst_sense_cachep);
|
||||
DEINIT_CACHEP(scst_aen_cachep);
|
||||
DEINIT_CACHEP(scst_cmd_cachep);
|
||||
DEINIT_CACHEP(scst_sess_cachep);
|
||||
DEINIT_CACHEP(scst_tgtd_cachep);
|
||||
|
||||
@@ -126,6 +126,7 @@ extern mempool_t *scst_mgmt_mempool;
|
||||
extern mempool_t *scst_mgmt_stub_mempool;
|
||||
extern mempool_t *scst_ua_mempool;
|
||||
extern mempool_t *scst_sense_mempool;
|
||||
extern mempool_t *scst_aen_mempool;
|
||||
|
||||
extern struct kmem_cache *scst_cmd_cachep;
|
||||
extern struct kmem_cache *scst_sess_cachep;
|
||||
@@ -190,9 +191,6 @@ extern int scst_cmd_threads_count(void);
|
||||
extern int __scst_add_cmd_threads(int num);
|
||||
extern void __scst_del_cmd_threads(int num);
|
||||
|
||||
extern spinlock_t scst_temp_UA_lock;
|
||||
extern uint8_t scst_temp_UA[SCST_SENSE_BUFFERSIZE];
|
||||
|
||||
extern struct scst_dev_type scst_null_devtype;
|
||||
|
||||
extern struct scst_cmd *__scst_check_deferred_commands(
|
||||
@@ -326,6 +324,7 @@ enum scst_sg_copy_dir {
|
||||
};
|
||||
void scst_copy_sg(struct scst_cmd *cmd, enum scst_sg_copy_dir);
|
||||
|
||||
uint64_t scst_pack_lun(const uint64_t lun);
|
||||
uint64_t scst_unpack_lun(const uint8_t *lun, int len);
|
||||
|
||||
struct scst_mgmt_cmd *scst_alloc_mgmt_cmd(gfp_t gfp_mask);
|
||||
@@ -357,10 +356,15 @@ static inline void scst_dev_check_set_UA(struct scst_device *dev,
|
||||
void scst_dev_check_set_local_UA(struct scst_device *dev,
|
||||
struct scst_cmd *exclude, const uint8_t *sense, int sense_len);
|
||||
|
||||
#define SCST_SET_UA_FLAG_AT_HEAD 1
|
||||
#define SCST_SET_UA_FLAG_GLOBAL 2
|
||||
|
||||
void scst_check_set_UA(struct scst_tgt_dev *tgt_dev,
|
||||
const uint8_t *sense, int sense_len, int head);
|
||||
const uint8_t *sense, int sense_len, int flags);
|
||||
int scst_set_pending_UA(struct scst_cmd *cmd);
|
||||
|
||||
void scst_report_luns_changed(struct scst_acg *acg);
|
||||
|
||||
void scst_abort_cmd(struct scst_cmd *cmd, struct scst_mgmt_cmd *mcmd,
|
||||
int other_ini, int call_dev_task_mgmt_fn);
|
||||
void scst_process_reset(struct scst_device *dev,
|
||||
|
||||
@@ -1321,13 +1321,12 @@ static void scst_cmd_done(void *data, char *sense, int result, int resid)
|
||||
if (cmd == NULL)
|
||||
goto out;
|
||||
|
||||
scst_do_cmd_done(cmd, result, sense, SCST_SENSE_BUFFERSIZE, resid);
|
||||
scst_do_cmd_done(cmd, result, sense, SCSI_SENSE_BUFFERSIZE, resid);
|
||||
|
||||
cmd->state = SCST_CMD_STATE_PRE_DEV_DONE;
|
||||
|
||||
scst_proccess_redirect_cmd(cmd,
|
||||
scst_optimize_post_exec_context(cmd, scst_estimate_context()),
|
||||
0);
|
||||
scst_optimize_post_exec_context(cmd, scst_estimate_context()), 0);
|
||||
|
||||
out:
|
||||
TRACE_EXIT();
|
||||
@@ -1490,6 +1489,37 @@ inc_dev_cnt:
|
||||
out_compl:
|
||||
cmd->completed = 1;
|
||||
|
||||
/* Clear left sense_reported_luns_data_changed UA, if any. */
|
||||
|
||||
mutex_lock(&scst_mutex); /* protect sess_tgt_dev_list_hash */
|
||||
for (i = 0; i < TGT_DEV_HASH_SIZE; i++) {
|
||||
struct list_head *sess_tgt_dev_list_head =
|
||||
&cmd->sess->sess_tgt_dev_list_hash[i];
|
||||
|
||||
list_for_each_entry(tgt_dev, sess_tgt_dev_list_head,
|
||||
sess_tgt_dev_list_entry) {
|
||||
struct scst_tgt_dev_UA *ua;
|
||||
|
||||
spin_lock_bh(&tgt_dev->tgt_dev_lock);
|
||||
list_for_each_entry(ua, &tgt_dev->UA_list,
|
||||
UA_list_entry) {
|
||||
if (scst_analyze_sense(ua->UA_sense_buffer,
|
||||
sizeof(ua->UA_sense_buffer),
|
||||
SCST_SENSE_ALL_VALID,
|
||||
SCST_LOAD_SENSE(scst_sense_reported_luns_data_changed))) {
|
||||
TRACE_MGMT_DBG("Freeing not needed "
|
||||
"REPORTED LUNS DATA CHANGED UA "
|
||||
"%p", ua);
|
||||
list_del(&ua->UA_list_entry);
|
||||
mempool_free(ua, scst_ua_mempool);
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock_bh(&tgt_dev->tgt_dev_lock);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&scst_mutex);
|
||||
|
||||
out_done:
|
||||
/* Report the result */
|
||||
cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT, SCST_CONTEXT_SAME);
|
||||
@@ -2275,7 +2305,10 @@ static int scst_check_sense(struct scst_cmd *cmd)
|
||||
|
||||
/* Check Unit Attention Sense Key */
|
||||
if (scst_is_ua_sense(cmd->sense)) {
|
||||
if (cmd->sense[12] == SCST_SENSE_ASC_UA_RESET) {
|
||||
if (scst_analyze_sense(cmd->sense,
|
||||
SCST_SENSE_BUFFERSIZE,
|
||||
SCST_SENSE_ASC_VALID,
|
||||
0, SCST_SENSE_ASC_UA_RESET, 0)) {
|
||||
if (cmd->double_ua_possible) {
|
||||
TRACE(TRACE_MGMT_MINOR, "Double UA "
|
||||
"detected for device %p", dev);
|
||||
@@ -2501,10 +2534,11 @@ static int scst_pre_dev_done(struct scst_cmd *cmd)
|
||||
(cmd->status == SAM_STAT_CHECK_CONDITION) &&
|
||||
SCST_SENSE_VALID(cmd->sense) &&
|
||||
scst_is_ua_sense(cmd->sense) &&
|
||||
(cmd->sense[12] == 0x2a) && (cmd->sense[13] == 0x01)) {
|
||||
TRACE(TRACE_SCSI,
|
||||
"MODE PARAMETERS CHANGED UA (lun %lld)",
|
||||
(long long unsigned int)cmd->lun);
|
||||
scst_analyze_sense(cmd->sense, SCST_SENSE_BUFFERSIZE,
|
||||
SCST_SENSE_ASCx_VALID,
|
||||
0, 0x2a, 0x01)) {
|
||||
TRACE(TRACE_SCSI, "MODE PARAMETERS CHANGED UA (lun "
|
||||
"%lld)", (long long unsigned int)cmd->lun);
|
||||
cmd->state = SCST_CMD_STATE_MODE_SELECT_CHECKS;
|
||||
goto out;
|
||||
}
|
||||
@@ -2529,6 +2563,8 @@ static int scst_mode_select_checks(struct scst_cmd *cmd)
|
||||
(cmd->cdb[0] == MODE_SELECT_10) ||
|
||||
(cmd->cdb[0] == LOG_SELECT))) {
|
||||
struct scst_device *dev = cmd->dev;
|
||||
uint8_t sense_buffer[SCST_STANDARD_SENSE_LEN];
|
||||
|
||||
if (atomic && (dev->scsi_dev != NULL)) {
|
||||
TRACE_DBG("%s", "MODE/LOG SELECT: thread "
|
||||
"context required");
|
||||
@@ -2541,19 +2577,17 @@ static int scst_mode_select_checks(struct scst_cmd *cmd)
|
||||
(long long unsigned int)cmd->lun);
|
||||
|
||||
spin_lock_bh(&dev->dev_lock);
|
||||
spin_lock(&scst_temp_UA_lock);
|
||||
if (cmd->cdb[0] == LOG_SELECT) {
|
||||
scst_set_sense(scst_temp_UA,
|
||||
sizeof(scst_temp_UA),
|
||||
scst_set_sense(sense_buffer,
|
||||
sizeof(sense_buffer),
|
||||
UNIT_ATTENTION, 0x2a, 0x02);
|
||||
} else {
|
||||
scst_set_sense(scst_temp_UA,
|
||||
sizeof(scst_temp_UA),
|
||||
scst_set_sense(sense_buffer,
|
||||
sizeof(sense_buffer),
|
||||
UNIT_ATTENTION, 0x2a, 0x01);
|
||||
}
|
||||
scst_dev_check_set_local_UA(dev, cmd, scst_temp_UA,
|
||||
sizeof(scst_temp_UA));
|
||||
spin_unlock(&scst_temp_UA_lock);
|
||||
scst_dev_check_set_local_UA(dev, cmd, sense_buffer,
|
||||
sizeof(sense_buffer));
|
||||
spin_unlock_bh(&dev->dev_lock);
|
||||
|
||||
if (dev->scsi_dev != NULL)
|
||||
@@ -2562,11 +2596,20 @@ static int scst_mode_select_checks(struct scst_cmd *cmd)
|
||||
} else if ((cmd->status == SAM_STAT_CHECK_CONDITION) &&
|
||||
SCST_SENSE_VALID(cmd->sense) &&
|
||||
scst_is_ua_sense(cmd->sense) &&
|
||||
(((cmd->sense[12] == 0x2a) && (cmd->sense[13] == 0x01)) ||
|
||||
(cmd->sense[12] == 0x29) /* reset */ ||
|
||||
(cmd->sense[12] == 0x28) /* medium changed */ ||
|
||||
/* mode parameters changed */
|
||||
(scst_analyze_sense(cmd->sense, SCST_SENSE_BUFFERSIZE,
|
||||
SCST_SENSE_ASCx_VALID,
|
||||
0, 0x2a, 0x01) ||
|
||||
scst_analyze_sense(cmd->sense, SCST_SENSE_BUFFERSIZE,
|
||||
SCST_SENSE_ASC_VALID,
|
||||
0, 0x29, 0) /* reset */ ||
|
||||
scst_analyze_sense(cmd->sense, SCST_SENSE_BUFFERSIZE,
|
||||
SCST_SENSE_ASC_VALID,
|
||||
0, 0x28, 0) /* medium changed */ ||
|
||||
/* cleared by another ini (just in case) */
|
||||
(cmd->sense[12] == 0x2F))) {
|
||||
scst_analyze_sense(cmd->sense, SCST_SENSE_BUFFERSIZE,
|
||||
SCST_SENSE_ASC_VALID,
|
||||
0, 0x2F, 0))) {
|
||||
if (atomic) {
|
||||
TRACE_DBG("Possible parameters changed UA %x: "
|
||||
"thread context required", cmd->sense[12]);
|
||||
@@ -2934,7 +2977,8 @@ static int scst_finish_cmd(struct scst_cmd *cmd)
|
||||
TRACE_MGMT_DBG("Requeuing UA for delivery failed cmd "
|
||||
"%p", cmd);
|
||||
scst_check_set_UA(cmd->tgt_dev, cmd->sense,
|
||||
SCST_SENSE_BUFFERSIZE, 1);
|
||||
SCST_SENSE_BUFFERSIZE,
|
||||
SCST_SET_UA_FLAG_AT_HEAD);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4192,14 +4236,15 @@ static int scst_clear_task_set(struct scst_mgmt_cmd *mcmd)
|
||||
mutex_unlock(&scst_mutex);
|
||||
|
||||
if (!dev->tas) {
|
||||
uint8_t sense_buffer[SCST_STANDARD_SENSE_LEN];
|
||||
|
||||
scst_set_sense(sense_buffer, sizeof(sense_buffer),
|
||||
SCST_LOAD_SENSE(scst_sense_cleared_by_another_ini_UA));
|
||||
|
||||
list_for_each_entry(tgt_dev, &UA_tgt_devs,
|
||||
extra_tgt_dev_list_entry) {
|
||||
spin_lock_bh(&scst_temp_UA_lock);
|
||||
scst_set_sense(scst_temp_UA, sizeof(scst_temp_UA),
|
||||
SCST_LOAD_SENSE(scst_sense_cleared_by_another_ini_UA));
|
||||
scst_check_set_UA(tgt_dev, scst_temp_UA,
|
||||
sizeof(scst_temp_UA), 0);
|
||||
spin_unlock_bh(&scst_temp_UA_lock);
|
||||
extra_tgt_dev_list_entry) {
|
||||
scst_check_set_UA(tgt_dev, sense_buffer,
|
||||
sizeof(sense_buffer), 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user