static struct page *dummy_page;
static struct scatterlist dummy_sg;
-static uint8_t sense_unexpected_unsolicited_data[SCST_STANDARD_SENSE_LEN];
+static uint8_t sense_fixed_unexpected_unsolicited_data[SCST_STANDARD_SENSE_LEN];
+static uint8_t sense_descr_unexpected_unsolicited_data[SCST_STANDARD_SENSE_LEN];
struct iscsi_thread_t {
struct task_struct *thr;
req->pdu.datasize)) {
PRINT_ERROR("Unexpected unsolicited data (ITT %x "
"CDB %x", cmnd_itt(req), req_hdr->scb[0]);
- create_status_rsp(req, SAM_STAT_CHECK_CONDITION,
- sense_unexpected_unsolicited_data,
- sizeof(sense_unexpected_unsolicited_data));
+ if (scst_get_cmd_dev_d_sense(scst_cmd))
+ create_status_rsp(req, SAM_STAT_CHECK_CONDITION,
+ sense_descr_unexpected_unsolicited_data,
+ sizeof(sense_descr_unexpected_unsolicited_data));
+ else
+ create_status_rsp(req, SAM_STAT_CHECK_CONDITION,
+ sense_fixed_unexpected_unsolicited_data,
+ sizeof(sense_fixed_unexpected_unsolicited_data));
cmnd_reject_scsi_cmd(req);
goto out;
}
if (unlikely(dir != SCST_DATA_WRITE)) {
PRINT_ERROR("pdu.datasize(%d) >0, but dir(%x) isn't "
"WRITE", req->pdu.datasize, dir);
- create_status_rsp(req, SAM_STAT_CHECK_CONDITION,
- sense_unexpected_unsolicited_data,
- sizeof(sense_unexpected_unsolicited_data));
+ if (scst_get_cmd_dev_d_sense(scst_cmd))
+ create_status_rsp(req, SAM_STAT_CHECK_CONDITION,
+ sense_descr_unexpected_unsolicited_data,
+ sizeof(sense_descr_unexpected_unsolicited_data));
+ else
+ create_status_rsp(req, SAM_STAT_CHECK_CONDITION,
+ sense_fixed_unexpected_unsolicited_data,
+ sizeof(sense_fixed_unexpected_unsolicited_data));
cmnd_reject_scsi_cmd(req);
} else
res = cmnd_prepare_recv_pdu(conn, req, 0,
PRINT_INFO("iSCSI SCST Target - version %s", ISCSI_VERSION_STRING);
- sense_unexpected_unsolicited_data[0] = 0x70;
- sense_unexpected_unsolicited_data[2] = ABORTED_COMMAND;
- sense_unexpected_unsolicited_data[7] = 6;
- sense_unexpected_unsolicited_data[12] = 0xc;
- sense_unexpected_unsolicited_data[13] = 0xc;
+ sense_fixed_unexpected_unsolicited_data[0] = 0x70;
+ sense_fixed_unexpected_unsolicited_data[2] = ABORTED_COMMAND;
+ sense_fixed_unexpected_unsolicited_data[7] = 6;
+ sense_fixed_unexpected_unsolicited_data[12] = 0xc;
+ sense_fixed_unexpected_unsolicited_data[13] = 0xc;
+
+ sense_descr_unexpected_unsolicited_data[0] = 0x72;
+ sense_descr_unexpected_unsolicited_data[1] = ABORTED_COMMAND;
+ sense_descr_unexpected_unsolicited_data[2] = 0xc;
+ sense_descr_unexpected_unsolicited_data[3] = 0xc;
dummy_page = alloc_pages(GFP_KERNEL, 0);
if (dummy_page == NULL) {
unsigned long tst:3;
unsigned long tas:1;
unsigned long swp:1;
+ unsigned long d_sense:1;
/*
* Set if device implements own ordered commands management. If not set
!test_bit(SCST_CMD_ABORTED_OTHER, &cmd->cmd_flags);
}
+/* Returns sense data format for cmd's dev */
+static inline bool scst_get_cmd_dev_d_sense(struct scst_cmd *cmd)
+{
+ return cmd->dev->d_sense;
+}
+
/*
* Get/Set functions for expected data direction, transfer length
* and its validity flag
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, bool d_sense,
+ 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);
+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
#define SCST_CONTR_MODE_QUEUE_ALG_RESTRICTED_REORDER 0
#define SCST_CONTR_MODE_QUEUE_ALG_UNRESTRICTED_REORDER 1
+/*************************************************************
+ ** Values for the control mode page D_SENSE field
+ *************************************************************/
+#define SCST_CONTR_MODE_FIXED_SENSE 0
+#define SCST_CONTR_MODE_DESCR_SENSE 1
+
/*************************************************************
** Misc SCSI constants
*************************************************************/
uint8_t queue_alg;
uint8_t tas;
uint8_t swp;
+ uint8_t d_sense;
uint8_t has_own_order_mgmt;
};
TRACE_DBG("READ_CAPACITY done: %x", res);
- if ((res == 0) || (sense_buffer[2] != UNIT_ATTENTION))
+ if ((res == 0) || !scst_analyze_sense(sense_buffer,
+ sizeof(sense_buffer), SCST_SENSE_KEY_VALID,
+ UNIT_ATTENTION, 0, 0))
break;
if (!--retries) {
TRACE_DBG("READ_CAPACITY done: %x", res);
- if (!res || (sense_buffer[12] != 0x28 &&
- sense_buffer[12] != 0x29))
+ if ((res == 0) || !scst_analyze_sense(sense_buffer,
+ sizeof(sense_buffer), SCST_SENSE_ALL_VALID,
+ SCST_LOAD_SENSE(scst_sense_medium_changed_UA)) ||
+ !scst_analyze_sense(sense_buffer, sizeof(sense_buffer),
+ SCST_SENSE_KEY_VALID | SCST_SENSE_ASC_VALID,
+ UNIT_ATTENTION, 0x29, 0))
break;
if (!--retries) {
PRINT_ERROR("UA not clear after %d retries",
TRACE_DBG("READ_CAPACITY done: %x", res);
- if (!res || (sense_buffer[2] != UNIT_ATTENTION))
+ if (!res || !scst_analyze_sense(sense_buffer,
+ sizeof(sense_buffer), SCST_SENSE_KEY_VALID,
+ UNIT_ATTENTION, 0, 0))
break;
if (!--retries) {
unsigned int queue_alg:4;
unsigned int tas:1;
unsigned int swp:1;
+ unsigned int d_sense:1;
unsigned int has_own_order_mgmt:1;
int (*generic_parse)(struct scst_cmd *cmd,
sdev->queue_alg = dev->queue_alg;
sdev->swp = dev->swp;
sdev->tas = dev->tas;
+ sdev->d_sense = dev->d_sense;
sdev->has_own_order_mgmt = dev->has_own_order_mgmt;
dev->sdev = sdev;
(opt->tst != SCST_CONTR_MODE_SEP_TASK_SETS)) ||
((opt->queue_alg != SCST_CONTR_MODE_QUEUE_ALG_RESTRICTED_REORDER) &&
(opt->queue_alg != SCST_CONTR_MODE_QUEUE_ALG_UNRESTRICTED_REORDER)) ||
- (opt->swp > 1) || (opt->tas > 1) || (opt->has_own_order_mgmt > 1)) {
+ (opt->swp > 1) || (opt->tas > 1) || (opt->has_own_order_mgmt > 1) ||
+ (opt->d_sense > 1)) {
PRINT_ERROR("Invalid SCSI option (tst %x, queue_alg %x, swp %x,"
- " tas %x, has_own_order_mgmt %x)", opt->tst,
- opt->queue_alg, opt->swp, opt->tas,
+ " tas %x, d_sense %d, has_own_order_mgmt %x)", opt->tst,
+ opt->queue_alg, opt->swp, opt->tas, opt->d_sense,
opt->has_own_order_mgmt);
res = -EINVAL;
goto out;
dev->queue_alg = opt->queue_alg;
dev->swp = opt->swp;
dev->tas = opt->tas;
+ dev->tst = opt->tst;
+ dev->d_sense = opt->d_sense;
dev->has_own_order_mgmt = opt->has_own_order_mgmt;
if (dev->sdev != NULL) {
dev->sdev->tst = opt->tst;
dev->sdev->queue_alg = opt->queue_alg;
dev->sdev->swp = opt->swp;
dev->sdev->tas = opt->tas;
+ dev->sdev->d_sense = opt->d_sense;
dev->sdev->has_own_order_mgmt = opt->has_own_order_mgmt;
}
opt.queue_alg = dev->queue_alg;
opt.tas = dev->tas;
opt.swp = dev->swp;
+ opt.d_sense = dev->d_sense;
opt.has_own_order_mgmt = dev->has_own_order_mgmt;
TRACE_DBG("dev %s, parse_type %x, on_free_cmd_type %x, "
#define DEF_SWP 0
#define DEF_TAS 0
+#define DEF_DSENSE SCST_CONTR_MODE_FIXED_SENSE
+
#define VDISK_PROC_HELP "help"
static unsigned int random_values[256] = {
dev->dh_priv = virt_dev;
dev->tst = DEF_TST;
+ dev->d_sense = DEF_DSENSE;
if (virt_dev->wt_flag && !virt_dev->nv_cache)
dev->queue_alg = DEF_QUEUE_ALG_WT;
else
goto out;
}
- scst_set_sense(address, length, SCST_LOAD_SENSE(scst_sense_no_sense));
+ scst_set_sense(address, length, cmd->dev->d_sense,
+ SCST_LOAD_SENSE(scst_sense_no_sense));
out_put:
scst_put_buf(cmd, address);
switch (pcontrol) {
case 0:
p[2] |= virt_dev->dev->tst << 5;
+ p[2] |= virt_dev->dev->d_sense << 2;
p[3] |= virt_dev->dev->queue_alg << 4;
p[4] |= virt_dev->dev->swp << 3;
p[5] |= virt_dev->dev->tas << 6;
p[2] |= 7 << 5; /* TST */
p[3] |= 0xF << 4; /* QUEUE ALGORITHM MODIFIER */
#endif
+ p[2] |= 1 << 2; /* D_SENSE */
p[4] |= 1 << 3; /* SWP */
p[5] |= 1 << 6; /* TAS */
break;
case 2:
p[2] |= DEF_TST << 5;
+ p[2] |= DEF_DSENSE << 2;
if (virt_dev->wt_flag || virt_dev->nv_cache)
p[3] |= DEF_QUEUE_ALG_WT << 4;
else
struct scst_vdisk_dev *virt_dev)
{
struct scst_device *dev = virt_dev->dev;
- int old_swp = dev->swp, old_tas = dev->tas;
+ int old_swp = dev->swp, old_tas = dev->tas, old_dsense = dev->d_sense;
#if 0
/* Not implemented yet, see comment in vdisk_ctrl_m_pg() */
#endif
dev->swp = (p[4] & 0x8) >> 3;
dev->tas = (p[5] & 0x40) >> 6;
+ dev->d_sense = (p[2] & 0x4) >> 2;
PRINT_INFO("Device %s: new control mode page parameters: SWP %x "
- "(was %x), TAS %x (was %x)", virt_dev->name, dev->swp,
- old_swp, dev->tas, old_tas);
+ "(was %x), TAS %x (was %x), D_SENSE %d (was %d)",
+ virt_dev->name, dev->swp, old_swp, dev->tas, old_tas,
+ dev->d_sense, old_dsense);
return;
}
struct scst_vdisk_dev *virt_dev =
(struct scst_vdisk_dev *)dev->dh_priv;
dev->tst = DEF_TST;
+ dev->d_sense = DEF_DSENSE;
if (virt_dev->wt_flag && !virt_dev->nv_cache)
dev->queue_alg = DEF_QUEUE_ALG_WT;
else
goto out;
}
- scst_set_sense(cmd->sense, SCST_SENSE_BUFFERSIZE, key, asc, ascq);
+ scst_set_sense(cmd->sense, SCST_SENSE_BUFFERSIZE, cmd->dev->d_sense,
+ key, asc, ascq);
TRACE_BUFFER("Sense set", cmd->sense, SCST_SENSE_BUFFERSIZE);
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, bool d_sense,
+ 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 */
+ if (d_sense) {
+ /* Descriptor format */
+ buffer[0] = 0x72; /* Response Code */
+ buffer[1] = key; /* Sense Key */
+ buffer[2] = asc; /* ASC */
+ buffer[3] = ascq; /* ASCQ */
+ } else {
+ /* Fixed format */
+ buffer[0] = 0x70; /* Response 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;
if (len < 14)
goto out;
- /* Error Code */
- if (sense[0] != 0x70)
- goto out;
+ /* Response Code */
+ if ((sense[0] == 0x70) || (sense[0] == 0x71)) {
+ /* Fixed format */
- /* Sense Key */
- if ((valid_mask & SCST_SENSE_KEY_VALID) && (sense[2] != key))
- 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;
+ /* 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;
+ } else if ((sense[0] == 0x72) || (sense[0] == 0x73)) {
+ /* Descriptor format */
- /* ASCQ */
- if ((valid_mask & SCST_SENSE_ASCQ_VALID) && (sense[13] != ascq))
+ /* Sense Key */
+ if ((valid_mask & SCST_SENSE_KEY_VALID) && (sense[1] != key))
+ goto out;
+
+ /* ASC */
+ if ((valid_mask & SCST_SENSE_ASC_VALID) && (sense[2] != asc))
+ goto out;
+
+ /* ASCQ */
+ if ((valid_mask & SCST_SENSE_ASCQ_VALID) && (sense[3] != ascq))
+ goto out;
+ } else
goto out;
res = true;
SCST_LOAD_SENSE(scst_sense_reset_UA))) {
scst_set_sense(ua->UA_sense_buffer,
sizeof(ua->UA_sense_buffer),
+ tgt_dev->dev->d_sense,
key, asc, ascq);
} else
PRINT_ERROR("%s",
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,
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)",
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_LOAD_SENSE(scst_sense_capacity_data_changed));
scst_check_set_UA(tgt_dev, sense_buffer,
sizeof(sense_buffer), 0);
}
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);
tgt_dev->dev->type))
continue;
+ scst_set_sense(sense_buffer, sizeof(sense_buffer),
+ tgt_dev->dev->d_sense,
+ SCST_LOAD_SENSE(scst_sense_reported_luns_data_changed));
+
__scst_check_set_UA(tgt_dev, sense_buffer,
sizeof(sense_buffer),
flags | SCST_SET_UA_FLAG_GLOBAL);
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_reported_luns_data_changed));
TRACE_DBG("Calling target's %s report_aen(%p)",
aen->sess->initiator_name);
if (scst_analyze_sense(aen->aen_sense, aen->aen_sense_len,
- SCST_SENSE_ALL_VALID,
- SCST_LOAD_SENSE(
+ 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_sense(sense_buffer, sizeof(sense_buffer),
- SCST_LOAD_SENSE(scst_sense_reset_UA));
+ dev->d_sense, SCST_LOAD_SENSE(scst_sense_reset_UA));
scst_alloc_set_UA(tgt_dev, sense_buffer, sizeof(sense_buffer), 0);
tm_dbg_init_tgt_dev(tgt_dev, acg_dev);
if (queue_UA) {
uint8_t sense_buffer[SCST_STANDARD_SENSE_LEN];
scst_set_sense(sense_buffer, sizeof(sense_buffer),
+ tgt_dev->dev->d_sense,
SCST_LOAD_SENSE(scst_sense_nexus_loss_UA));
scst_check_set_UA(tgt_dev, sense_buffer,
sizeof(sense_buffer), 0);
if (host_byte(result) == DID_RESET) {
TRACE(TRACE_MGMT_MINOR, "%s", "DID_RESET received, triggering "
"reset UA");
- scst_set_sense(sense, sense_len,
+ scst_set_sense(sense, sense_len, dev->d_sense,
SCST_LOAD_SENSE(scst_sense_reset_UA));
scst_dev_check_set_UA(dev, NULL, sense, sense_len);
} else if ((status_byte(result) == CHECK_CONDITION) &&
dev->queue_alg = q;
dev->swp = (buffer[4+4] & 0x8) >> 3;
dev->tas = (buffer[4+5] & 0x40) >> 6;
+ dev->d_sense = (buffer[4+2] & 0x4) >> 2;
/*
* Unfortunately, SCSI ML doesn't provide a way to
TRACE(TRACE_SCSI|TRACE_MGMT_MINOR,
"Device %d:%d:%d:%d: TST %x, "
- "QUEUE ALG %x, SWP %x, TAS %x, "
+ "QUEUE ALG %x, SWP %x, TAS %x, D_SENSE %d"
"has_own_order_mgmt %d",
dev->scsi_dev->host->host_no,
dev->scsi_dev->channel, dev->scsi_dev->id,
dev->scsi_dev->lun, dev->tst, dev->queue_alg,
- dev->swp, dev->tas, dev->has_own_order_mgmt);
+ dev->swp, dev->tas, dev->d_sense,
+ dev->has_own_order_mgmt);
goto out;
} else {
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,"
- " using defaults: TST %x,"
- " QUEUE ALG %x, SWP %x, TAS %x,"
- " has_own_order_mgmt %d",
+ "Device %d:%d:%d:%d doesn't "
+ "support control mode page, "
+ "using defaults: TST %x, "
+ "QUEUE ALG %x, SWP %x, "
+ "TAS %x, D_SENSE %d, "
+ "has_own_order_mgmt %d ",
dev->scsi_dev->host->host_no,
dev->scsi_dev->channel,
dev->scsi_dev->id,
dev->scsi_dev->lun,
- dev->tst,
- dev->queue_alg,
- dev->swp,
- dev->tas,
+ dev->tst, dev->queue_alg,
+ dev->swp, dev->tas,
+ dev->d_sense,
dev->has_own_order_mgmt);
res = 0;
goto out;
if (setUA) {
uint8_t sense_buffer[SCST_STANDARD_SENSE_LEN];
scst_set_sense(sense_buffer, sizeof(sense_buffer),
- SCST_LOAD_SENSE(scst_sense_reset_UA));
+ dev->d_sense, SCST_LOAD_SENSE(scst_sense_reset_UA));
scst_dev_check_set_local_UA(dev, exclude_cmd, sense_buffer,
sizeof(sense_buffer));
}
if (cmd->cdb[0] == LOG_SELECT) {
scst_set_sense(sense_buffer,
sizeof(sense_buffer),
+ dev->d_sense,
UNIT_ATTENTION, 0x2a, 0x02);
} else {
scst_set_sense(sense_buffer,
sizeof(sense_buffer),
+ dev->d_sense,
UNIT_ATTENTION, 0x2a, 0x01);
}
scst_dev_check_set_local_UA(dev, cmd, sense_buffer,
if (!dev->tas) {
uint8_t sense_buffer[SCST_STANDARD_SENSE_LEN];
- scst_set_sense(sense_buffer, sizeof(sense_buffer),
+ scst_set_sense(sense_buffer, sizeof(sense_buffer), dev->d_sense,
SCST_LOAD_SENSE(scst_sense_cleared_by_another_ini_UA));
list_for_each_entry(tgt_dev, &UA_tgt_devs,
desc.opt.tst = SCST_CONTR_MODE_SEP_TASK_SETS;
desc.opt.queue_alg = SCST_CONTR_MODE_QUEUE_ALG_UNRESTRICTED_REORDER;
+ desc.opt.d_sense = SCST_CONTR_MODE_FIXED_SENSE;
res = ioctl(dev.scst_usr_fd, SCST_USER_REGISTER_DEVICE, &desc);
if (res != 0) {