SCSI cleanups and improvements

git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@4334 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Vladislav Bolkhovitin
2012-06-06 01:11:09 +00:00
parent d8218039b0
commit 27f0a660e4
4 changed files with 114 additions and 42 deletions

View File

@@ -2343,7 +2343,7 @@ static enum compl_status_e vdisk_exec_inquiry(struct vdisk_cmd_params *p)
if (virt_dev->removable)
buf[1] = 0x80; /* removable */
buf[2] = 5; /* Device complies to SPC-3 */
buf[2] = 6; /* Device complies to SPC-4 */
buf[3] = 0x02; /* Data in format specified in SPC */
if (cmd->tgtt->fake_aca)
buf[3] |= 0x20;
@@ -2390,9 +2390,9 @@ static enum compl_status_e vdisk_exec_inquiry(struct vdisk_cmd_params *p)
buf[4] += 58 - 36;
num = 0;
/* SAM-3 T10/1561-D revision 14 */
/* SAM-4 T10/1683-D revision 14 */
buf[58 + num] = 0x0;
buf[58 + num + 1] = 0x76;
buf[58 + num + 1] = 0x8B;
num += 2;
/* Physical transport */
@@ -2411,9 +2411,9 @@ static enum compl_status_e vdisk_exec_inquiry(struct vdisk_cmd_params *p)
num += 2;
}
/* SPC-3 T10/1416-D revision 23 */
buf[58 + num] = 0x3;
buf[58 + num + 1] = 0x12;
/* SPC-4 T10/1731-D revision 23 */
buf[58 + num] = 0x4;
buf[58 + num + 1] = 0x63;
num += 2;
/* Device command set */
@@ -2956,13 +2956,16 @@ static enum compl_status_e vdisk_exec_read_capacity(struct vdisk_cmd_params *p)
/* Last block on the virt_dev is (nblocks-1) */
memset(buffer, 0, sizeof(buffer));
#if 0 /* we don't need this workaround anymore */
/*
* If we are thinly provisioned, we must ensure that the initiator
* issues a READ_CAPACITY(16) so we can return the TPE bit. By
* issues a READ_CAPACITY(16) so we can return the LBPME bit. By
* returning 0xFFFFFFFF we do that.
*/
put_unaligned_be32(nblocks >> 32 || virt_dev->thin_provisioned ?
0xffffffffU : nblocks - 1, &buffer[0]);
#endif
put_unaligned_be32(blocksize, &buffer[4]);
length = scst_get_buf_full(cmd, &address);
@@ -3037,14 +3040,14 @@ static enum compl_status_e vdisk_exec_read_capacity16(struct vdisk_cmd_params *p
}
if (virt_dev->thin_provisioned) {
buffer[14] |= 0x80; /* Add TPE */
buffer[14] |= 0x80; /* Add LBPME */
#if 0 /*
* Might be a big performance and functionality win, but might be
* dangerous as well, although generally nearly always it should be set,
* because nearly all devices should return zero for unmapped blocks.
* But let's be on the safe side and disable it for now.
*/
buffer[14] |= 0x40; /* Add TPRZ */
buffer[14] |= 0x40; /* Add LBPRZ */
#endif
}

View File

@@ -1633,6 +1633,16 @@ int scst_set_sense(uint8_t *buffer, int len, bool d_sense,
memset(buffer, 0, len);
/*
* The RESPONSE CODE field shall be set to 70h in all unit attention
* condition sense data in which:
* a) the ADDITIONAL SENSE CODE field is set to 29h; or
* b) the additional sense code is set to MODE PARAMETERS CHANGED.
*/
if ((key == UNIT_ATTENTION) &&
((asc == 0x29) || ((asc == 0x2A) && (ascq == 1))))
d_sense = false;
if (d_sense) {
/* Descriptor format */
if (len < 8) {
@@ -1794,8 +1804,17 @@ void scst_check_convert_sense(struct scst_cmd *cmd)
if ((cmd->sense == NULL) || (cmd->status != SAM_STAT_CHECK_CONDITION))
goto out;
/*
* The RESPONSE CODE field shall be set to 70h in all unit attention
* condition sense data in which:
* a) the ADDITIONAL SENSE CODE field is set to 29h; or
* b) the additional sense code is set to MODE PARAMETERS CHANGED.
*/
d_sense = scst_get_cmd_dev_d_sense(cmd);
if (d_sense && ((cmd->sense[0] == 0x70) || (cmd->sense[0] == 0x71))) {
if (d_sense && ((cmd->sense[0] == 0x70) || (cmd->sense[0] == 0x71)) &&
!((cmd->sense[2] == UNIT_ATTENTION) &&
((cmd->sense[12] == 0x29) ||
((cmd->sense[12] == 0x2A) && (cmd->sense[13] == 1))))) {
TRACE_MGMT_DBG("Converting fixed sense to descriptor (cmd %p)",
cmd);
if ((cmd->sense_valid_len < 18)) {
@@ -2280,12 +2299,16 @@ out_free:
}
EXPORT_SYMBOL(scst_aen_done);
void scst_requeue_ua(struct scst_cmd *cmd)
void scst_requeue_ua(struct scst_cmd *cmd, const uint8_t *buf, int size)
{
TRACE_ENTRY();
if (scst_analyze_sense(cmd->sense, cmd->sense_valid_len,
SCST_SENSE_ALL_VALID,
if (buf == NULL) {
buf = cmd->sense;
size = cmd->sense_valid_len;
}
if (scst_analyze_sense(buf, size, SCST_SENSE_ALL_VALID,
SCST_LOAD_SENSE(scst_sense_reported_luns_data_changed))) {
TRACE_MGMT_DBG("Requeuing REPORTED LUNS DATA CHANGED UA "
"for delivery failed cmd %p", cmd);
@@ -2295,8 +2318,7 @@ void scst_requeue_ua(struct scst_cmd *cmd)
mutex_unlock(&scst_mutex);
} else {
TRACE_MGMT_DBG("Requeuing UA for delivery failed cmd %p", cmd);
scst_check_set_UA(cmd->tgt_dev, cmd->sense,
cmd->sense_valid_len, SCST_SET_UA_FLAG_AT_HEAD);
scst_check_set_UA(cmd->tgt_dev, buf, size, SCST_SET_UA_FLAG_AT_HEAD);
}
TRACE_EXIT();
@@ -4628,7 +4650,7 @@ static void scst_ws_write_cmd_finished(struct scst_cmd *cmd)
if (rc != 0) {
/* Requeue possible UA */
if (scst_is_ua_sense(cmd->sense, cmd->sense_buflen))
scst_requeue_ua(cmd);
scst_requeue_ua(cmd, NULL, 0);
}
}
@@ -7330,7 +7352,7 @@ void scst_tgt_dev_del_free_UA(struct scst_tgt_dev *tgt_dev,
}
/* No locks, no IRQ or IRQ-disabled context allowed */
int scst_set_pending_UA(struct scst_cmd *cmd)
int scst_set_pending_UA(struct scst_cmd *cmd, uint8_t *buf, int *size)
{
int res = 0, i;
struct scst_tgt_dev_UA *UA_entry;
@@ -7399,9 +7421,23 @@ again:
goto again;
}
if (scst_set_cmd_error_sense(cmd, UA_entry->UA_sense_buffer,
UA_entry->UA_valid_sense_len) != 0)
goto out_unlock;
if (buf == NULL) {
if (scst_set_cmd_error_sense(cmd, UA_entry->UA_sense_buffer,
UA_entry->UA_valid_sense_len) != 0)
goto out_unlock;
} else {
sBUG_ON(*size == 0);
if (UA_entry->UA_valid_sense_len > *size) {
TRACE(TRACE_MINOR, "%s: Being returned UA truncated "
"to size %d (needed %d)", cmd->op_name,
*size, UA_entry->UA_valid_sense_len);
*size = UA_entry->UA_valid_sense_len;
}
TRACE_DBG_SPECIAL("Returning UA in buffer %p (size %d)",
buf, *size); //!!!
memcpy(buf, UA_entry->UA_sense_buffer, *size);
*size = UA_entry->UA_valid_sense_len;
}
cmd->ua_ignore = 1;

View File

@@ -574,7 +574,7 @@ void scst_dev_check_set_local_UA(struct scst_device *dev,
void scst_check_set_UA(struct scst_tgt_dev *tgt_dev,
const uint8_t *sense, int sense_len, int flags);
int scst_set_pending_UA(struct scst_cmd *cmd);
int scst_set_pending_UA(struct scst_cmd *cmd, uint8_t *buf, int *size);
void scst_report_luns_changed(struct scst_acg *acg);
@@ -585,7 +585,7 @@ void scst_process_reset(struct scst_device *dev,
struct scst_mgmt_cmd *mcmd, bool setUA);
bool scst_is_ua_global(const uint8_t *sense, int len);
void scst_requeue_ua(struct scst_cmd *cmd);
void scst_requeue_ua(struct scst_cmd *cmd, const uint8_t *buf, int size);
struct scst_aen *scst_alloc_aen(struct scst_session *sess,
uint64_t unpacked_lun);

View File

@@ -1839,21 +1839,53 @@ static int scst_request_sense_local(struct scst_cmd *cmd)
cmd->host_status = DID_OK;
cmd->driver_status = 0;
spin_lock_bh(&tgt_dev->tgt_dev_lock);
if (tgt_dev->tgt_dev_valid_sense_len == 0)
goto out_unlock_not_completed;
TRACE(TRACE_SCSI, "%s: Returning stored sense", cmd->op_name);
buffer_size = scst_get_buf_full(cmd, &buffer);
if (unlikely(buffer_size == 0))
goto out_unlock_compl;
goto out_compl;
else if (unlikely(buffer_size < 0))
goto out_unlock_hw_err;
goto out_hw_err;
memset(buffer, 0, buffer_size);
spin_lock_bh(&tgt_dev->tgt_dev_lock);
if (tgt_dev->tgt_dev_valid_sense_len == 0) {
if (test_bit(SCST_TGT_DEV_UA_PENDING, &cmd->tgt_dev->tgt_dev_flags)) {
int rc, size = sizeof(tgt_dev->tgt_dev_sense);
uint8_t *buf;
spin_unlock_bh(&tgt_dev->tgt_dev_lock);
buf = kzalloc(size, GFP_KERNEL);
if (buf == NULL)
goto out_put_busy;
rc = scst_set_pending_UA(cmd, buf, &size);
spin_lock_bh(&tgt_dev->tgt_dev_lock);
if (rc == 0) {
if (tgt_dev->tgt_dev_valid_sense_len == 0) {
tgt_dev->tgt_dev_valid_sense_len = size;
memcpy(tgt_dev->tgt_dev_sense, buf, size);
} else {
/*
* Yes, we can loose some of UA data
* here, if UA size is bigger, than
* size, i.e. tgt_dev_sense.
*/
scst_requeue_ua(cmd, buf, size);
}
}
kfree(buf);
}
if (tgt_dev->tgt_dev_valid_sense_len == 0)
goto out_unlock_put_not_completed;
}
TRACE(TRACE_SCSI, "%s: Returning stored/UA sense", cmd->op_name);
if (((tgt_dev->tgt_dev_sense[0] == 0x70) ||
(tgt_dev->tgt_dev_sense[0] == 0x71)) && (cmd->cdb[1] & 1)) {
PRINT_WARNING("%s: Fixed format of the saved sense, but "
@@ -1890,12 +1922,12 @@ static int scst_request_sense_local(struct scst_cmd *cmd)
memcpy(buffer, tgt_dev->tgt_dev_sense, sl);
}
scst_put_buf_full(cmd, buffer);
tgt_dev->tgt_dev_valid_sense_len = 0;
spin_unlock_bh(&tgt_dev->tgt_dev_lock);
scst_put_buf_full(cmd, buffer);
scst_set_resp_data_len(cmd, sl);
out_compl:
@@ -1908,19 +1940,20 @@ out:
TRACE_EXIT_RES(res);
return res;
out_unlock_hw_err:
spin_unlock_bh(&tgt_dev->tgt_dev_lock);
out_hw_err:
scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error));
goto out_compl;
out_unlock_not_completed:
out_put_busy:
scst_put_buf_full(cmd, buffer);
scst_set_busy(cmd);
goto out_compl;
out_unlock_put_not_completed:
spin_unlock_bh(&tgt_dev->tgt_dev_lock);
scst_put_buf_full(cmd, buffer);
res = SCST_EXEC_NOT_COMPLETED;
goto out;
out_unlock_compl:
spin_unlock_bh(&tgt_dev->tgt_dev_lock);
goto out_compl;
}
static int scst_reserve_local(struct scst_cmd *cmd)
@@ -2420,7 +2453,7 @@ int __scst_check_local_events(struct scst_cmd *cmd, bool preempt_tests_only)
if (unlikely(test_bit(SCST_TGT_DEV_UA_PENDING,
&cmd->tgt_dev->tgt_dev_flags))) {
if (scst_is_ua_command(cmd)) {
rc = scst_set_pending_UA(cmd);
rc = scst_set_pending_UA(cmd, NULL, NULL);
if (rc == 0)
goto out_complete;
}
@@ -3706,7 +3739,7 @@ static int scst_finish_cmd(struct scst_cmd *cmd)
res = SCST_CMD_STATE_RES_NEED_THREAD;
goto out;
}
scst_requeue_ua(cmd);
scst_requeue_ua(cmd, NULL, 0);
}
}