diff --git a/scst/README b/scst/README index 7e29272ce..6e6adb685 100644 --- a/scst/README +++ b/scst/README @@ -162,6 +162,14 @@ IMPORTANT: In the current version simultaneous access to local SCSI devices devices READ/WRITE commands using direct disk handler look to be safe. +IMPORTANT: Some versions of Windows have a bug, which makes them consider +========= response of READ CAPACITY(16) longer than 12 bytes as a faulty one. + As the result, such Windows'es refuse to see SCST exported + devices >2TB in size. This is fixed by MS in latter Windows + versions, probably, by some hotfix. But if you're using such + buggy Windows and experience this problem, change this '1' to + '0'. + To uninstall, type 'make scst_uninstall'. diff --git a/scst/include/scst.h b/scst/include/scst.h index 983111394..c26c4091a 100644 --- a/scst/include/scst.h +++ b/scst/include/scst.h @@ -1392,7 +1392,8 @@ struct scst_cmd { uint8_t driver_status; /* set by mid-level */ uint8_t *sense; /* pointer to sense buffer */ - unsigned short sense_bufflen; /* length of the sense buffer, if any */ + unsigned short sense_valid_len; /* length of valid sense data */ + unsigned short sense_buflen; /* length of the sense buffer, if any */ /* Start time when cmd was sent to rdy_to_xfer() or xmit_response() */ unsigned long hw_pending_start; @@ -1764,9 +1765,11 @@ struct scst_tgt_dev_UA { struct list_head UA_list_entry; /* Set if UA is global for session */ - unsigned int global_UA:1; + unsigned short global_UA:1; - /* Unit Attention sense */ + /* Unit Attention valid sense len */ + unsigned short UA_valid_sense_len; + /* Unit Attention sense buf */ uint8_t UA_sense_buffer[SCST_SENSE_BUFFERSIZE]; }; @@ -2146,7 +2149,7 @@ enum dma_data_direction scst_to_dma_dir(int scst_dir); enum dma_data_direction scst_to_tgt_dma_dir(int scst_dir); /* - * Returns 1, if cmd's CDB is locally handled by SCST and 0 otherwise. + * Returns true, if cmd's CDB is locally handled by SCST and 0 otherwise. * Dev handlers parse() and dev_done() not called for such commands. */ static inline bool scst_is_cmd_local(struct scst_cmd *cmd) @@ -2154,6 +2157,12 @@ static inline bool scst_is_cmd_local(struct scst_cmd *cmd) return (cmd->op_flags & SCST_LOCAL_CMD) != 0; } +/* Returns true, if cmd can deliver UA */ +static inline bool scst_is_ua_command(struct scst_cmd *cmd) +{ + return (cmd->op_flags & SCST_SKIP_UA) == 0; +} + /* * Registers a virtual device. * Parameters: @@ -2455,10 +2464,10 @@ static inline uint8_t *scst_cmd_get_sense_buffer(struct scst_cmd *cmd) return cmd->sense; } -/* Returns cmd's sense buffer length */ +/* Returns cmd's valid sense length */ static inline int scst_cmd_get_sense_buffer_len(struct scst_cmd *cmd) { - return cmd->sense_bufflen; + return cmd->sense_valid_len; } /* @@ -3020,7 +3029,11 @@ 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, bool d_sense, +/* + * Sets the corresponding field in the sense buffer taking sense type + * into account. Returns resulting sense length. + */ +int scst_set_sense(uint8_t *buffer, int len, bool d_sense, int key, int asc, int ascq); /* diff --git a/scst/include/scst_const.h b/scst/include/scst_const.h index a5ad17f98..ab738f212 100644 --- a/scst/include/scst_const.h +++ b/scst/include/scst_const.h @@ -39,7 +39,7 @@ * Size of sense sufficient to carry standard sense data. * Warning! It's allocated on stack! */ -#define SCST_STANDARD_SENSE_LEN 17 +#define SCST_STANDARD_SENSE_LEN 18 /* Max size of sense */ #define SCST_SENSE_BUFFERSIZE 96 diff --git a/scst/src/dev_handlers/scst_cdrom.c b/scst/src/dev_handlers/scst_cdrom.c index a73deaff3..cef3f9f23 100644 --- a/scst/src/dev_handlers/scst_cdrom.c +++ b/scst/src/dev_handlers/scst_cdrom.c @@ -117,7 +117,8 @@ static int cdrom_attach(struct scst_device *dev) TRACE_DBG("READ_CAPACITY done: %x", res); - if ((res == 0) || !scst_analyze_sense(sense_buffer, + if ((res == 0) || + !scst_analyze_sense(sense_buffer, sizeof(sense_buffer), SCST_SENSE_KEY_VALID, UNIT_ATTENTION, 0, 0)) break; @@ -141,7 +142,8 @@ 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", sense_buffer, sizeof(sense_buffer)); + TRACE_BUFFER("Returned sense", sense_buffer, + sizeof(sense_buffer)); params->block_shift = CDROM_DEF_BLOCK_SHIFT; } diff --git a/scst/src/dev_handlers/scst_disk.c b/scst/src/dev_handlers/scst_disk.c index cba330a15..ce5ea2c1c 100644 --- a/scst/src/dev_handlers/scst_disk.c +++ b/scst/src/dev_handlers/scst_disk.c @@ -193,7 +193,8 @@ static int disk_attach(struct scst_device *dev) TRACE_DBG("READ_CAPACITY done: %x", res); - if ((res == 0) || !scst_analyze_sense(sense_buffer, + 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), @@ -216,7 +217,8 @@ static int disk_attach(struct scst_device *dev) params->block_shift = scst_calc_block_shift(sector_size); } else { - TRACE_BUFFER("Sense set", sense_buffer, sizeof(sense_buffer)); + TRACE_BUFFER("Returned sense", sense_buffer, + sizeof(sense_buffer)); res = -ENODEV; goto out_free_buf; } diff --git a/scst/src/dev_handlers/scst_modisk.c b/scst/src/dev_handlers/scst_modisk.c index 99f5eb360..222dba66d 100644 --- a/scst/src/dev_handlers/scst_modisk.c +++ b/scst/src/dev_handlers/scst_modisk.c @@ -230,7 +230,8 @@ 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", sense_buffer, sizeof(sense_buffer)); + TRACE_BUFFER("Returned sense", sense_buffer, + sizeof(sense_buffer)); if (sense_buffer[2] != NOT_READY) { res = -ENODEV; diff --git a/scst/src/dev_handlers/scst_user.c b/scst/src/dev_handlers/scst_user.c index 71bf61e7e..4eb7a656c 100644 --- a/scst/src/dev_handlers/scst_user.c +++ b/scst/src/dev_handlers/scst_user.c @@ -1360,16 +1360,22 @@ static int dev_user_process_reply_exec(struct scst_user_cmd *ucmd, cmd->status = ereply->status; if (ereply->sense_len != 0) { + int sense_len; + res = scst_alloc_sense(cmd, 0); if (res != 0) goto out_compl; + + sense_len = min((int)cmd->sense_buflen, (int)ereply->sense_len); + res = copy_from_user(cmd->sense, (void __user *)(unsigned long)ereply->psense_buffer, - min((int)cmd->sense_bufflen, (int)ereply->sense_len)); + sense_len); if (res < 0) { PRINT_ERROR("%s", "Unable to get sense data"); goto out_hwerr_res_set; } + cmd->sense_valid_len = sense_len; } out_compl: diff --git a/scst/src/dev_handlers/scst_vdisk.c b/scst/src/dev_handlers/scst_vdisk.c index fb2a25705..c80811aae 100644 --- a/scst/src/dev_handlers/scst_vdisk.c +++ b/scst/src/dev_handlers/scst_vdisk.c @@ -1116,8 +1116,7 @@ static int vcdrom_exec(struct scst_cmd *cmd) goto out_done; } - if (virt_dev->media_changed && (cmd->cdb[0] != INQUIRY) && - (cmd->cdb[0] != REQUEST_SENSE) && (cmd->cdb[0] != REPORT_LUNS)) { + if (virt_dev->media_changed && scst_is_ua_command(cmd)) { spin_lock(&virt_dev->flags_lock); if (virt_dev->media_changed) { virt_dev->media_changed = 0; @@ -1335,31 +1334,28 @@ out: static void vdisk_exec_request_sense(struct scst_cmd *cmd) { - int32_t length; + int32_t length, sl; uint8_t *address; + uint8_t b[SCST_STANDARD_SENSE_LEN]; TRACE_ENTRY(); - length = scst_get_buf_first(cmd, &address); - TRACE_DBG("length %d", length); - if (unlikely(length < SCST_STANDARD_SENSE_LEN)) { - if (length != 0) { - PRINT_ERROR("scst_get_buf_first() failed or too small " - "requested buffer (returned %d)", length); - scst_set_cmd_error(cmd, - SCST_LOAD_SENSE( - scst_sense_invalid_field_in_parm_list)); - } - if (length > 0) - goto out_put; - else - goto out; - } - - scst_set_sense(address, length, cmd->dev->d_sense, + sl = scst_set_sense(b, sizeof(b), cmd->dev->d_sense, SCST_LOAD_SENSE(scst_sense_no_sense)); -out_put: + length = scst_get_buf_first(cmd, &address); + TRACE_DBG("length %d", length); + if (length < 0) { + PRINT_ERROR("scst_get_buf_first() failed: %d)", length); + scst_set_cmd_error(cmd, + SCST_LOAD_SENSE(scst_sense_hardw_error)); + goto out; + } + + length = min(sl, length); + memcpy(address, b, length); + scst_set_resp_data_len(cmd, length); + scst_put_buf(cmd, address); out: @@ -1935,8 +1931,23 @@ static void vdisk_exec_read_capacity16(struct scst_cmd *cmd) goto out; } + /* + * Some versions of Windows have a bug, which makes them consider + * response of READ CAPACITY(16) longer than 12 bytes as a faulty one. + * As the result, such Windows'es refuse to see SCST exported + * devices >2TB in size. This is fixed by MS in latter Windows + * versions, probably, by some hotfix. + * + * But if you're using such buggy Windows and experience this problem, + * change this '1' to '0'. + */ +#if 1 if (length > READ_CAP16_LEN) length = READ_CAP16_LEN; +#else + if (length > 12) + length = 12; +#endif memcpy(address, buffer, length); scst_put_buf(cmd, address); diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index 1b7b02d1d..e494c5de3 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -91,9 +91,11 @@ int scst_alloc_sense(struct scst_cmd *cmd, int atomic) goto out; } + cmd->sense_buflen = SCST_SENSE_BUFFERSIZE; + memzero: - cmd->sense_bufflen = SCST_SENSE_BUFFERSIZE; - memset(cmd->sense, 0, SCST_SENSE_BUFFERSIZE); + cmd->sense_valid_len = 0; + memset(cmd->sense, 0, cmd->sense_buflen); out: TRACE_EXIT_RES(res); @@ -114,8 +116,15 @@ int scst_alloc_set_sense(struct scst_cmd *cmd, int atomic, goto out; } - memcpy(cmd->sense, sense, min((int)len, (int)cmd->sense_bufflen)); - TRACE_BUFFER("Sense set", cmd->sense, cmd->sense_bufflen); + cmd->sense_valid_len = len; + if (cmd->sense_buflen < len) { + PRINT_WARNING("Sense truncated (needed %d), shall you increase " + "SCST_SENSE_BUFFERSIZE? Op: %x", len, cmd->cdb[0]); + cmd->sense_valid_len = cmd->sense_buflen; + } + + memcpy(cmd->sense, sense, cmd->sense_valid_len); + TRACE_BUFFER("Sense set", cmd->sense, cmd->sense_valid_len); out: TRACE_EXIT_RES(res); @@ -159,9 +168,9 @@ void scst_set_cmd_error(struct scst_cmd *cmd, int key, int asc, int ascq) goto out; } - scst_set_sense(cmd->sense, cmd->sense_bufflen, + cmd->sense_valid_len = scst_set_sense(cmd->sense, cmd->sense_buflen, scst_get_cmd_dev_d_sense(cmd), key, asc, ascq); - TRACE_BUFFER("Sense set", cmd->sense, cmd->sense_bufflen); + TRACE_BUFFER("Sense set", cmd->sense, cmd->sense_valid_len); out: TRACE_EXIT(); @@ -169,16 +178,18 @@ out: } EXPORT_SYMBOL(scst_set_cmd_error); -void scst_set_sense(uint8_t *buffer, int len, bool d_sense, +int scst_set_sense(uint8_t *buffer, int len, bool d_sense, int key, int asc, int ascq) { + int res; + sBUG_ON(len == 0); memset(buffer, 0, len); if (d_sense) { /* Descriptor format */ - if (len < 4) { + if (len < 8) { PRINT_ERROR("Length %d of sense buffer too small to " "fit sense %x:%x:%x", len, key, asc, ascq); } @@ -190,9 +201,10 @@ void scst_set_sense(uint8_t *buffer, int len, bool d_sense, buffer[2] = asc; /* ASC */ if (len > 3) buffer[3] = ascq; /* ASCQ */ + res = 8; } else { /* Fixed format */ - if (len < 14) { + if (len < 18) { PRINT_ERROR("Length %d of sense buffer too small to " "fit sense %x:%x:%x", len, key, asc, ascq); } @@ -206,10 +218,11 @@ void scst_set_sense(uint8_t *buffer, int len, bool d_sense, buffer[12] = asc; /* ASC */ if (len > 13) buffer[13] = ascq; /* ASCQ */ + res = 18; } - TRACE_BUFFER("Sense set", buffer, len); - return; + TRACE_BUFFER("Sense set", buffer, res); + return res; } EXPORT_SYMBOL(scst_set_sense); @@ -222,43 +235,55 @@ bool scst_analyze_sense(const uint8_t *sense, int len, unsigned int valid_mask, if ((sense[0] == 0x70) || (sense[0] == 0x71)) { /* Fixed format */ - if (len < 14) { - PRINT_ERROR("Sense too small to analyze (%d, " - "type fixed)", len); - goto out; + /* Sense Key */ + if (valid_mask & SCST_SENSE_KEY_VALID) { + if (len < 3) + goto out; + if (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; + if (valid_mask & SCST_SENSE_ASC_VALID) { + if (len < 13) + goto out; + if (sense[12] != asc) + goto out; + } /* ASCQ */ - if ((valid_mask & SCST_SENSE_ASCQ_VALID) && (sense[13] != ascq)) - goto out; + if (valid_mask & SCST_SENSE_ASCQ_VALID) { + if (len < 14) + goto out; + if (sense[13] != ascq) + goto out; + } } else if ((sense[0] == 0x72) || (sense[0] == 0x73)) { /* Descriptor format */ - if (len < 4) { - PRINT_ERROR("Sense too small to analyze (%d, " - "type descriptor)", len); - goto out; + /* Sense Key */ + if (valid_mask & SCST_SENSE_KEY_VALID) { + if (len < 2) + goto out; + if (sense[1] != key) + goto out; } - /* 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; + if (valid_mask & SCST_SENSE_ASC_VALID) { + if (len < 3) + goto out; + if (sense[2] != asc) + goto out; + } /* ASCQ */ - if ((valid_mask & SCST_SENSE_ASCQ_VALID) && (sense[3] != ascq)) - goto out; + if (valid_mask & SCST_SENSE_ASCQ_VALID) { + if (len < 4) + goto out; + if (sense[3] != ascq) + goto out; + } } else goto out; @@ -308,23 +333,25 @@ void scst_check_convert_sense(struct scst_cmd *cmd) if (d_sense && ((cmd->sense[0] == 0x70) || (cmd->sense[0] == 0x71))) { TRACE_MGMT_DBG("Converting fixed sense to descriptor (cmd %p)", cmd); - if (cmd->sense_bufflen < 14) { + if ((cmd->sense_valid_len < 18) ) { PRINT_ERROR("Sense too small to convert (%d, " - "type fixed)", cmd->sense_bufflen); + "type: fixed)", cmd->sense_buflen); goto out; } - scst_set_sense(cmd->sense, cmd->sense_bufflen, d_sense, - cmd->sense[2], cmd->sense[12], cmd->sense[13]); + cmd->sense_valid_len = scst_set_sense(cmd->sense, cmd->sense_buflen, + d_sense, cmd->sense[2], cmd->sense[12], cmd->sense[13]); } else if (!d_sense && ((cmd->sense[0] == 0x72) || (cmd->sense[0] == 0x73))) { TRACE_MGMT_DBG("Converting descriptor sense to fixed (cmd %p)", cmd); - if (cmd->sense_bufflen < 4) { + if ((cmd->sense_buflen < 18) || (cmd->sense_valid_len < 8)) { PRINT_ERROR("Sense too small to convert (%d, " - "type descryptor)", cmd->sense_bufflen); + "type: descryptor, valid %d)", + cmd->sense_buflen, cmd->sense_valid_len); goto out; } - scst_set_sense(cmd->sense, cmd->sense_bufflen, d_sense, + cmd->sense_valid_len = scst_set_sense(cmd->sense, + cmd->sense_buflen, d_sense, cmd->sense[1], cmd->sense[2], cmd->sense[3]); } @@ -397,10 +424,11 @@ void scst_set_initial_UA(struct scst_session *sess, int key, int asc, int ascq) ua = list_entry(tgt_dev->UA_list.next, typeof(*ua), UA_list_entry); if (scst_analyze_sense(ua->UA_sense_buffer, - sizeof(ua->UA_sense_buffer), + ua->UA_valid_sense_len, SCST_SENSE_ALL_VALID, SCST_LOAD_SENSE(scst_sense_reset_UA))) { - scst_set_sense(ua->UA_sense_buffer, + ua->UA_valid_sense_len = scst_set_sense( + ua->UA_sense_buffer, sizeof(ua->UA_sense_buffer), tgt_dev->dev->d_sense, key, asc, ascq); @@ -464,6 +492,7 @@ void scst_gen_aen_or_ua(struct scst_tgt_dev *tgt_dev, { struct scst_tgt_template *tgtt = tgt_dev->sess->tgt->tgtt; uint8_t sense_buffer[SCST_STANDARD_SENSE_LEN]; + int sl; TRACE_ENTRY(); @@ -476,9 +505,9 @@ void scst_gen_aen_or_ua(struct scst_tgt_dev *tgt_dev, 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, - tgt_dev->dev->d_sense, key, asc, ascq); + aen->aen_sense_len = scst_set_sense(aen->aen_sense, + SCST_SENSE_BUFFERSIZE, tgt_dev->dev->d_sense, + key, asc, ascq); TRACE_DBG("Calling target's %s report_aen(%p)", tgtt->name, aen); @@ -494,9 +523,9 @@ void scst_gen_aen_or_ua(struct scst_tgt_dev *tgt_dev, queue_ua: TRACE_MGMT_DBG("AEN not supported, queuing plain UA (tgt_dev %p)", tgt_dev); - scst_set_sense(sense_buffer, sizeof(sense_buffer), + sl = scst_set_sense(sense_buffer, sizeof(sense_buffer), tgt_dev->dev->d_sense, key, asc, ascq); - scst_check_set_UA(tgt_dev, sense_buffer, sizeof(sense_buffer), 0); + scst_check_set_UA(tgt_dev, sense_buffer, sl, 0); out: TRACE_EXIT(); @@ -585,17 +614,18 @@ static void scst_queue_report_luns_changed_UA(struct scst_session *sess, list_for_each_entry(tgt_dev, shead, sess_tgt_dev_list_entry) { + int sl; + if (!scst_is_report_luns_changed_type( tgt_dev->dev->type)) continue; - scst_set_sense(sense_buffer, sizeof(sense_buffer), + sl = 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); + sl, flags | SCST_SET_UA_FLAG_GLOBAL); } } @@ -653,8 +683,8 @@ found: 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, d_sense, + aen->aen_sense_len = scst_set_sense(aen->aen_sense, + SCST_SENSE_BUFFERSIZE, d_sense, SCST_LOAD_SENSE(scst_sense_reported_luns_data_changed)); TRACE_DBG("Calling target's %s report_aen(%p)", @@ -754,7 +784,7 @@ void scst_requeue_ua(struct scst_cmd *cmd) { TRACE_ENTRY(); - if (scst_analyze_sense(cmd->sense, cmd->sense_bufflen, + if (scst_analyze_sense(cmd->sense, cmd->sense_valid_len, SCST_SENSE_ALL_VALID, SCST_LOAD_SENSE(scst_sense_reported_luns_data_changed))) { TRACE_MGMT_DBG("Requeuing REPORTED LUNS DATA CHANGED UA " @@ -766,7 +796,7 @@ void scst_requeue_ua(struct scst_cmd *cmd) } else { TRACE_MGMT_DBG("Requeuing UA for delivery failed cmd %p", cmd); scst_check_set_UA(cmd->tgt_dev, cmd->sense, - cmd->sense_bufflen, SCST_SET_UA_FLAG_AT_HEAD); + cmd->sense_valid_len, SCST_SET_UA_FLAG_AT_HEAD); } TRACE_EXIT(); @@ -1428,7 +1458,7 @@ static struct scst_tgt_dev *scst_alloc_add_tgt_dev(struct scst_session *sess, struct scst_device *dev = acg_dev->dev; struct list_head *sess_tgt_dev_list_head; struct scst_tgt_template *vtt = sess->tgt->tgtt; - int rc, i; + int rc, i, sl; bool share_io_ctx = false; uint8_t sense_buffer[SCST_STANDARD_SENSE_LEN]; @@ -1523,9 +1553,9 @@ static struct scst_tgt_dev *scst_alloc_add_tgt_dev(struct scst_session *sess, &tgt_dev->tgt_dev_flags); } - scst_set_sense(sense_buffer, sizeof(sense_buffer), + sl = scst_set_sense(sense_buffer, sizeof(sense_buffer), dev->d_sense, SCST_LOAD_SENSE(scst_sense_reset_UA)); - scst_alloc_set_UA(tgt_dev, sense_buffer, sizeof(sense_buffer), 0); + scst_alloc_set_UA(tgt_dev, sense_buffer, sl, 0); tm_dbg_init_tgt_dev(tgt_dev, acg_dev); @@ -1635,11 +1665,10 @@ void scst_nexus_loss(struct scst_tgt_dev *tgt_dev, bool queue_UA) 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); + int sl = 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, sl, 0); } TRACE_EXIT(); @@ -4272,11 +4301,12 @@ static void scst_check_internal_sense(struct scst_device *dev, int result, TRACE_ENTRY(); if (host_byte(result) == DID_RESET) { + int sl; TRACE(TRACE_MGMT_MINOR, "%s", "DID_RESET received, triggering " "reset UA"); - scst_set_sense(sense, sense_len, dev->d_sense, + sl = 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); + scst_dev_check_set_UA(dev, NULL, sense, sl); } else if ((status_byte(result) == CHECK_CONDITION) && scst_is_ua_sense(sense, sense_len)) scst_dev_check_set_UA(dev, NULL, sense, sense_len); @@ -4526,10 +4556,9 @@ void scst_process_reset(struct scst_device *dev, if (setUA) { uint8_t sense_buffer[SCST_STANDARD_SENSE_LEN]; - scst_set_sense(sense_buffer, sizeof(sense_buffer), + int sl = scst_set_sense(sense_buffer, sizeof(sense_buffer), dev->d_sense, SCST_LOAD_SENSE(scst_sense_reset_UA)); - scst_dev_check_set_local_UA(dev, exclude_cmd, sense_buffer, - sizeof(sense_buffer)); + scst_dev_check_set_local_UA(dev, exclude_cmd, sense_buffer, sl); } TRACE_EXIT(); @@ -4595,7 +4624,7 @@ again: } scst_set_cmd_error_sense(cmd, UA_entry->UA_sense_buffer, - sizeof(UA_entry->UA_sense_buffer)); + UA_entry->UA_valid_sense_len); cmd->ua_ignore = 1; @@ -4614,8 +4643,8 @@ again: UA_list_entry) { if (ua->global_UA && memcmp(ua->UA_sense_buffer, - UA_entry->UA_sense_buffer, - sizeof(ua->UA_sense_buffer)) == 0) { + UA_entry->UA_sense_buffer, + sizeof(ua->UA_sense_buffer)) == 0) { TRACE_MGMT_DBG("Freeing not " "needed global UA %p", ua); @@ -4679,9 +4708,13 @@ static void scst_alloc_set_UA(struct scst_tgt_dev *tgt_dev, if (UA_entry->global_UA) TRACE_MGMT_DBG("Queuing global UA %p", UA_entry); - if (sense_len > (int)sizeof(UA_entry->UA_sense_buffer)) + if (sense_len > (int)sizeof(UA_entry->UA_sense_buffer)) { + PRINT_WARNING("Sense truncated (needed %d), shall you increase " + "SCST_SENSE_BUFFERSIZE?", sense_len); sense_len = sizeof(UA_entry->UA_sense_buffer); + } memcpy(UA_entry->UA_sense_buffer, sense, sense_len); + UA_entry->UA_valid_sense_len = sense_len; set_bit(SCST_TGT_DEV_UA_PENDING, &tgt_dev->tgt_dev_flags); @@ -5239,13 +5272,13 @@ void scst_store_sense(struct scst_cmd *cmd) spin_lock_bh(&tgt_dev->tgt_dev_lock); - if (cmd->sense_bufflen <= sizeof(tgt_dev->tgt_dev_sense)) - tgt_dev->tgt_dev_valid_sense_len = cmd->sense_bufflen; + if (cmd->sense_valid_len <= sizeof(tgt_dev->tgt_dev_sense)) + tgt_dev->tgt_dev_valid_sense_len = cmd->sense_valid_len; else { tgt_dev->tgt_dev_valid_sense_len = sizeof(tgt_dev->tgt_dev_sense); PRINT_ERROR("Stored sense truncated to size %d " "(needed %d)", tgt_dev->tgt_dev_valid_sense_len, - cmd->sense_bufflen); + cmd->sense_valid_len); } memcpy(tgt_dev->tgt_dev_sense, cmd->sense, tgt_dev->tgt_dev_valid_sense_len); diff --git a/scst/src/scst_priv.h b/scst/src/scst_priv.h index 468ecce97..154466a7c 100644 --- a/scst/src/scst_priv.h +++ b/scst/src/scst_priv.h @@ -436,11 +436,6 @@ void scst_requeue_ua(struct scst_cmd *cmd); void scst_gen_aen_or_ua(struct scst_tgt_dev *tgt_dev, int key, int asc, int ascq); -static inline bool scst_is_ua_command(struct scst_cmd *cmd) -{ - return (cmd->op_flags & SCST_SKIP_UA) == 0; -} - static inline bool scst_is_implicit_hq(struct scst_cmd *cmd) { return (cmd->op_flags & SCST_IMPLICIT_HQ) != 0; diff --git a/scst/src/scst_targ.c b/scst/src/scst_targ.c index 6262717f3..4f28898e7 100644 --- a/scst/src/scst_targ.c +++ b/scst/src/scst_targ.c @@ -1509,7 +1509,7 @@ out_compl: 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), + ua->UA_valid_sense_len, SCST_SENSE_ALL_VALID, SCST_LOAD_SENSE(scst_sense_reported_luns_data_changed))) { TRACE_MGMT_DBG("Freeing not needed " @@ -1553,7 +1553,7 @@ static int scst_request_sense_local(struct scst_cmd *cmd) int res = SCST_EXEC_COMPLETED, rc; struct scst_tgt_dev *tgt_dev = cmd->tgt_dev; uint8_t *buffer; - int buffer_size = 0; + int buffer_size = 0, sl; TRACE_ENTRY(); @@ -1590,7 +1590,7 @@ static int scst_request_sense_local(struct scst_cmd *cmd) tgt_dev->tgt_dev_valid_sense_len); buffer_size = min(SCST_STANDARD_SENSE_LEN, buffer_size); - scst_set_sense(buffer, buffer_size, true, + sl = scst_set_sense(buffer, buffer_size, true, tgt_dev->tgt_dev_sense[2], tgt_dev->tgt_dev_sense[12], tgt_dev->tgt_dev_sense[13]); } else if (((tgt_dev->tgt_dev_sense[0] == 0x72) || @@ -1602,25 +1602,26 @@ static int scst_request_sense_local(struct scst_cmd *cmd) tgt_dev->tgt_dev_valid_sense_len); buffer_size = min(SCST_STANDARD_SENSE_LEN, buffer_size); - scst_set_sense(buffer, buffer_size, false, + sl = scst_set_sense(buffer, buffer_size, false, tgt_dev->tgt_dev_sense[1], tgt_dev->tgt_dev_sense[2], tgt_dev->tgt_dev_sense[3]); } else { if (buffer_size >= tgt_dev->tgt_dev_valid_sense_len) - buffer_size = tgt_dev->tgt_dev_valid_sense_len; + sl = tgt_dev->tgt_dev_valid_sense_len; else { + sl = buffer_size; PRINT_WARNING("%s: Being returned sense truncated to " "size %d (needed %d)", cmd->op_name, buffer_size, tgt_dev->tgt_dev_valid_sense_len); } - memcpy(buffer, tgt_dev->tgt_dev_sense, buffer_size); + memcpy(buffer, tgt_dev->tgt_dev_sense, sl); } scst_put_buf(cmd, buffer); out_compl: tgt_dev->tgt_dev_valid_sense_len = 0; - scst_set_resp_data_len(cmd, buffer_size); + scst_set_resp_data_len(cmd, sl); spin_unlock_bh(&tgt_dev->tgt_dev_lock); @@ -2420,11 +2421,11 @@ static int scst_check_sense(struct scst_cmd *cmd) if (unlikely(cmd->status == SAM_STAT_CHECK_CONDITION) && SCST_SENSE_VALID(cmd->sense)) { PRINT_BUFF_FLAG(TRACE_SCSI, "Sense", cmd->sense, - cmd->sense_bufflen); + cmd->sense_valid_len); /* Check Unit Attention Sense Key */ - if (scst_is_ua_sense(cmd->sense, cmd->sense_bufflen)) { - if (scst_analyze_sense(cmd->sense, cmd->sense_bufflen, + if (scst_is_ua_sense(cmd->sense, cmd->sense_valid_len)) { + if (scst_analyze_sense(cmd->sense, cmd->sense_valid_len, SCST_SENSE_ASC_VALID, 0, SCST_SENSE_ASC_UA_RESET, 0)) { if (cmd->double_ua_possible) { @@ -2458,7 +2459,7 @@ static int scst_check_sense(struct scst_cmd *cmd) } } scst_dev_check_set_UA(dev, cmd, cmd->sense, - cmd->sense_bufflen); + cmd->sense_valid_len); } } @@ -2633,7 +2634,7 @@ static int scst_pre_dev_done(struct scst_cmd *cmd) (long long unsigned int)cmd->lun, cmd->status); PRINT_BUFF_FLAG(TRACE_SCSI, "Sense", cmd->sense, - cmd->sense_bufflen); + cmd->sense_valid_len); /* Clearing the reservation */ spin_lock_bh(&dev->dev_lock); @@ -2651,8 +2652,8 @@ static int scst_pre_dev_done(struct scst_cmd *cmd) /* Check for MODE PARAMETERS CHANGED UA */ if ((cmd->dev->scsi_dev != NULL) && (cmd->status == SAM_STAT_CHECK_CONDITION) && - scst_is_ua_sense(cmd->sense, cmd->sense_bufflen) && - scst_analyze_sense(cmd->sense, cmd->sense_bufflen, + scst_is_ua_sense(cmd->sense, cmd->sense_valid_len) && + scst_analyze_sense(cmd->sense, cmd->sense_valid_len, SCST_SENSE_ASCx_VALID, 0, 0x2a, 0x01)) { TRACE(TRACE_SCSI, "MODE PARAMETERS CHANGED UA (lun " @@ -2681,6 +2682,7 @@ 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; + int sl; uint8_t sense_buffer[SCST_STANDARD_SENSE_LEN]; if (atomic && (dev->scsi_dev != NULL)) { @@ -2696,37 +2698,36 @@ static int scst_mode_select_checks(struct scst_cmd *cmd) spin_lock_bh(&dev->dev_lock); if (cmd->cdb[0] == LOG_SELECT) { - scst_set_sense(sense_buffer, + sl = scst_set_sense(sense_buffer, sizeof(sense_buffer), dev->d_sense, UNIT_ATTENTION, 0x2a, 0x02); } else { - scst_set_sense(sense_buffer, + sl = 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, - sizeof(sense_buffer)); + scst_dev_check_set_local_UA(dev, cmd, sense_buffer, sl); spin_unlock_bh(&dev->dev_lock); if (dev->scsi_dev != NULL) scst_obtain_device_parameters(dev); } } else if ((cmd->status == SAM_STAT_CHECK_CONDITION) && - scst_is_ua_sense(cmd->sense, cmd->sense_bufflen) && + scst_is_ua_sense(cmd->sense, cmd->sense_valid_len) && /* mode parameters changed */ - (scst_analyze_sense(cmd->sense, cmd->sense_bufflen, + (scst_analyze_sense(cmd->sense, cmd->sense_valid_len, SCST_SENSE_ASCx_VALID, 0, 0x2a, 0x01) || - scst_analyze_sense(cmd->sense, cmd->sense_bufflen, + scst_analyze_sense(cmd->sense, cmd->sense_valid_len, SCST_SENSE_ASC_VALID, 0, 0x29, 0) /* reset */ || - scst_analyze_sense(cmd->sense, cmd->sense_bufflen, + scst_analyze_sense(cmd->sense, cmd->sense_valid_len, SCST_SENSE_ASC_VALID, 0, 0x28, 0) /* medium changed */ || /* cleared by another ini (just in case) */ - scst_analyze_sense(cmd->sense, cmd->sense_bufflen, + scst_analyze_sense(cmd->sense, cmd->sense_valid_len, SCST_SENSE_ASC_VALID, 0, 0x2F, 0))) { if (atomic) { @@ -3110,10 +3111,10 @@ static int scst_finish_cmd(struct scst_cmd *cmd) if (unlikely(cmd->delivery_status != SCST_CMD_DELIVERY_SUCCESS)) { if ((cmd->tgt_dev != NULL) && - scst_is_ua_sense(cmd->sense, cmd->sense_bufflen)) { + scst_is_ua_sense(cmd->sense, cmd->sense_valid_len)) { /* This UA delivery failed, so we need to requeue it */ if (scst_cmd_atomic(cmd) && - scst_is_ua_global(cmd->sense, cmd->sense_bufflen)) { + scst_is_ua_global(cmd->sense, cmd->sense_valid_len)) { TRACE_MGMT_DBG("Requeuing of global UA for " "failed cmd %p needs a thread", cmd); res = SCST_CMD_STATE_RES_NEED_THREAD; @@ -4407,14 +4408,15 @@ static int scst_clear_task_set(struct scst_mgmt_cmd *mcmd) if (!dev->tas) { uint8_t sense_buffer[SCST_STANDARD_SENSE_LEN]; + int sl; - scst_set_sense(sense_buffer, sizeof(sense_buffer), dev->d_sense, + sl = 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, extra_tgt_dev_list_entry) { - scst_check_set_UA(tgt_dev, sense_buffer, - sizeof(sense_buffer), 0); + scst_check_set_UA(tgt_dev, sense_buffer, sl, 0); } } diff --git a/usr/fileio/common.c b/usr/fileio/common.c index ca730b661..6ef62dcb8 100644 --- a/usr/fileio/common.c +++ b/usr/fileio/common.c @@ -125,7 +125,7 @@ static inline void set_cmd_error_status(struct scst_user_scsi_cmd_reply_exec *re static int set_sense(uint8_t *buffer, int len, int key, int asc, int ascq) { - int res = SCST_STANDARD_SENSE_LEN; + int res = 18; EXTRACHECKS_BUG_ON(len < res); @@ -1064,23 +1064,18 @@ static void exec_request_sense(struct vdisk_cmd *vcmd) { struct scst_user_scsi_cmd_exec *cmd = &vcmd->cmd->exec_cmd; struct scst_user_scsi_cmd_reply_exec *reply = &vcmd->reply->exec_reply; - int length = cmd->bufflen; + int length = cmd->bufflen, l; uint8_t *address = (uint8_t*)(unsigned long)cmd->pbuf; + uint8_t b[SCST_STANDARD_SENSE_LEN]; TRACE_ENTRY(); - if (length < SCST_STANDARD_SENSE_LEN) { - PRINT_ERROR("too small requested buffer for REQUEST SENSE " - "(len %d)", length); - set_cmd_error(vcmd, - SCST_LOAD_SENSE(scst_sense_invalid_field_in_parm_list)); - goto out; - } + l = set_sense(b, sizeof(b), SCST_LOAD_SENSE(scst_sense_no_sense)); - set_sense(address, length, SCST_LOAD_SENSE(scst_sense_no_sense)); + length = min(l, length); + memcpy(address, b, length); reply->resp_data_len = length; -out: TRACE_EXIT(); return; }