diff --git a/scst/src/dev_handlers/scst_vdisk.c b/scst/src/dev_handlers/scst_vdisk.c index 5bb0ff773..7eff0bea4 100644 --- a/scst/src/dev_handlers/scst_vdisk.c +++ b/scst/src/dev_handlers/scst_vdisk.c @@ -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 } diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index 95395246e..8d6034027 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -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; diff --git a/scst/src/scst_priv.h b/scst/src/scst_priv.h index 7124e151b..5202da96d 100644 --- a/scst/src/scst_priv.h +++ b/scst/src/scst_priv.h @@ -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); diff --git a/scst/src/scst_targ.c b/scst/src/scst_targ.c index 211bdb19c..7c494e705 100644 --- a/scst/src/scst_targ.c +++ b/scst/src/scst_targ.c @@ -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); } }