Improve length handling when writing sense data.

- Allow maximal sense size limitation via Control Extension mode page.
 - When sense size limited, include descriptors atomically: whole or none.
 - Set new SDAT_OVFL bit if some descriptors don't fit the limit.
 - Report real written sense length instead of static maximal 252 bytes.

MFC after:	2 weeks
This commit is contained in:
Alexander Motin 2016-12-24 17:42:34 +00:00
parent d97b8afd73
commit 4fc0d1d757
6 changed files with 341 additions and 356 deletions

View file

@ -278,7 +278,7 @@ const static struct scsi_control_ext_page control_ext_page_changeable = {
/*page_length*/{CTL_CEM_LEN >> 8, CTL_CEM_LEN},
/*flags*/0,
/*prio*/0,
/*max_sense*/0
/*max_sense*/0xff
};
const static struct scsi_info_exceptions_page ie_page_default = {
@ -9220,6 +9220,7 @@ ctl_request_sense(struct ctl_scsiio *ctsio)
struct ctl_lun *lun;
uint32_t initidx;
int have_error;
u_int sense_len = SSD_FULL_SIZE;
scsi_sense_data_type sense_format;
ctl_ua_type ua_type;
uint8_t asc = 0, ascq = 0;
@ -9263,7 +9264,7 @@ ctl_request_sense(struct ctl_scsiio *ctsio)
((lun->flags & CTL_LUN_PRIMARY_SC) == 0 &&
softc->ha_link < CTL_HA_LINK_UNKNOWN)) {
/* "Logical unit not supported" */
ctl_set_sense_data(sense_ptr, NULL, sense_format,
ctl_set_sense_data(sense_ptr, &sense_len, NULL, sense_format,
/*current_error*/ 1,
/*sense_key*/ SSD_KEY_ILLEGAL_REQUEST,
/*asc*/ 0x25,
@ -9319,7 +9320,8 @@ ctl_request_sense(struct ctl_scsiio *ctsio)
} else
#endif
if (have_error == 0) {
ua_type = ctl_build_ua(lun, initidx, sense_ptr, sense_format);
ua_type = ctl_build_ua(lun, initidx, sense_ptr, &sense_len,
sense_format);
if (ua_type != CTL_UA_NONE)
have_error = 1;
}
@ -9331,7 +9333,7 @@ ctl_request_sense(struct ctl_scsiio *ctsio)
asc = lun->ie_asc;
ascq = lun->ie_ascq;
}
ctl_set_sense_data(sense_ptr, lun, sense_format,
ctl_set_sense_data(sense_ptr, &sense_len, lun, sense_format,
/*current_error*/ 1,
/*sense_key*/ SSD_KEY_NO_SENSE,
/*asc*/ asc,
@ -11635,14 +11637,15 @@ ctl_scsiio_precheck(struct ctl_softc *softc, struct ctl_scsiio *ctsio)
*/
if ((entry->flags & CTL_CMD_FLAG_NO_SENSE) == 0) {
ctl_ua_type ua_type;
u_int sense_len = 0;
ua_type = ctl_build_ua(lun, initidx, &ctsio->sense_data,
SSD_TYPE_NONE);
&sense_len, SSD_TYPE_NONE);
if (ua_type != CTL_UA_NONE) {
mtx_unlock(&lun->lun_lock);
ctsio->scsi_status = SCSI_STATUS_CHECK_COND;
ctsio->io_hdr.status = CTL_SCSI_ERROR | CTL_AUTOSENSE;
ctsio->sense_len = SSD_FULL_SIZE;
ctsio->sense_len = sense_len;
ctl_done((union ctl_io *)ctsio);
return (retval);
}

View file

@ -65,9 +65,9 @@ __FBSDID("$FreeBSD$");
#include <cam/ctl/ctl_private.h>
void
ctl_set_sense_data_va(struct scsi_sense_data *sense_data, void *lunptr,
scsi_sense_data_type sense_format, int current_error,
int sense_key, int asc, int ascq, va_list ap)
ctl_set_sense_data_va(struct scsi_sense_data *sense_data, u_int *sense_len,
void *lunptr, scsi_sense_data_type sense_format, int current_error,
int sense_key, int asc, int ascq, va_list ap)
{
struct ctl_lun *lun;
@ -89,20 +89,30 @@ ctl_set_sense_data_va(struct scsi_sense_data *sense_data, void *lunptr,
sense_format = SSD_TYPE_FIXED;
}
scsi_set_sense_data_va(sense_data, sense_format, current_error,
sense_key, asc, ascq, ap);
/*
* Determine maximum sense data length to return.
*/
if (*sense_len == 0) {
if ((lun != NULL) && (lun->MODE_CTRLE.max_sense != 0))
*sense_len = lun->MODE_CTRLE.max_sense;
else
*sense_len = SSD_FULL_SIZE;
}
scsi_set_sense_data_va(sense_data, sense_len, sense_format,
current_error, sense_key, asc, ascq, ap);
}
void
ctl_set_sense_data(struct scsi_sense_data *sense_data, void *lunptr,
scsi_sense_data_type sense_format, int current_error,
int sense_key, int asc, int ascq, ...)
ctl_set_sense_data(struct scsi_sense_data *sense_data, u_int *sense_len,
void *lunptr, scsi_sense_data_type sense_format, int current_error,
int sense_key, int asc, int ascq, ...)
{
va_list ap;
va_start(ap, ascq);
ctl_set_sense_data_va(sense_data, lunptr, sense_format, current_error,
sense_key, asc, ascq, ap);
ctl_set_sense_data_va(sense_data, sense_len, lunptr, sense_format,
current_error, sense_key, asc, ascq, ap);
va_end(ap);
}
@ -112,6 +122,7 @@ ctl_set_sense(struct ctl_scsiio *ctsio, int current_error, int sense_key,
{
va_list ap;
struct ctl_lun *lun;
u_int sense_len;
/*
* The LUN can't go away until all of the commands have been
@ -121,7 +132,8 @@ ctl_set_sense(struct ctl_scsiio *ctsio, int current_error, int sense_key,
lun = (struct ctl_lun *)ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr;
va_start(ap, ascq);
ctl_set_sense_data_va(&ctsio->sense_data,
sense_len = 0;
ctl_set_sense_data_va(&ctsio->sense_data, &sense_len,
lun,
SSD_TYPE_NONE,
current_error,
@ -132,7 +144,7 @@ ctl_set_sense(struct ctl_scsiio *ctsio, int current_error, int sense_key,
va_end(ap);
ctsio->scsi_status = SCSI_STATUS_CHECK_COND;
ctsio->sense_len = SSD_FULL_SIZE;
ctsio->sense_len = sense_len;
ctsio->io_hdr.status = CTL_SCSI_ERROR | CTL_AUTOSENSE;
}
@ -148,6 +160,7 @@ ctl_sense_to_desc(struct scsi_sense_data_fixed *sense_src,
{
struct scsi_sense_stream stream_sense;
int current_error;
u_int sense_len;
uint8_t stream_bits;
bzero(sense_dest, sizeof(*sense_dest));
@ -173,7 +186,8 @@ ctl_sense_to_desc(struct scsi_sense_data_fixed *sense_src,
* value is set in the fixed sense data, set it in the descriptor
* data. Otherwise, skip it.
*/
ctl_set_sense_data((struct scsi_sense_data *)sense_dest,
sense_len = SSD_FULL_SIZE;
ctl_set_sense_data((struct scsi_sense_data *)sense_dest, &sense_len,
/*lun*/ NULL,
/*sense_format*/ SSD_TYPE_DESC,
current_error,
@ -233,6 +247,7 @@ ctl_sense_to_fixed(struct scsi_sense_data_desc *sense_src,
int info_size = 0, cmd_size = 0, fru_size = 0;
int sks_size = 0, stream_size = 0;
int pos;
u_int sense_len;
if ((sense_src->error_code & SSD_ERRCODE) == SSD_DESC_CURRENT_ERROR)
current_error = 1;
@ -318,7 +333,8 @@ ctl_sense_to_fixed(struct scsi_sense_data_desc *sense_src,
}
}
ctl_set_sense_data((struct scsi_sense_data *)sense_dest,
sense_len = SSD_FULL_SIZE;
ctl_set_sense_data((struct scsi_sense_data *)sense_dest, &sense_len,
/*lun*/ NULL,
/*sense_format*/ SSD_TYPE_FIXED,
current_error,
@ -501,12 +517,13 @@ ctl_build_qae(struct ctl_lun *lun, uint32_t initidx, uint8_t *resp)
resp[0] |= 0x20;
resp[1] = asc;
resp[2] = ascq;
return (ua);
return (ua_to_build);
}
ctl_ua_type
ctl_build_ua(struct ctl_lun *lun, uint32_t initidx,
struct scsi_sense_data *sense, scsi_sense_data_type sense_format)
struct scsi_sense_data *sense, u_int *sense_len,
scsi_sense_data_type sense_format)
{
ctl_ua_type *ua;
ctl_ua_type ua_to_build, ua_to_clear;
@ -540,7 +557,7 @@ ctl_build_ua(struct ctl_lun *lun, uint32_t initidx,
info = NULL;
ctl_ua_to_ascq(lun, ua_to_build, &asc, &ascq, &ua_to_clear, &info);
ctl_set_sense_data(sense, lun, sense_format, /*current_error*/ 1,
ctl_set_sense_data(sense, sense_len, lun, sense_format, 1,
/*sense_key*/ SSD_KEY_UNIT_ATTENTION, asc, ascq,
((info != NULL) ? SSD_ELEM_INFO : SSD_ELEM_SKIP), 8, info,
SSD_ELEM_NONE);

View file

@ -45,12 +45,12 @@
struct ctl_lun;
void ctl_set_sense_data_va(struct scsi_sense_data *sense_data, void *lun,
scsi_sense_data_type sense_format, int current_error,
int sense_key, int asc, int ascq, va_list ap);
void ctl_set_sense_data(struct scsi_sense_data *sense_data, void *lun,
scsi_sense_data_type sense_format, int current_error,
int sense_key, int asc, int ascq, ...);
void ctl_set_sense_data_va(struct scsi_sense_data *sense_data, u_int *sense_len,
void *lun, scsi_sense_data_type sense_format, int current_error,
int sense_key, int asc, int ascq, va_list ap);
void ctl_set_sense_data(struct scsi_sense_data *sense_data, u_int *sense_len,
void *lun, scsi_sense_data_type sense_format, int current_error,
int sense_key, int asc, int ascq, ...);
void ctl_set_sense(struct ctl_scsiio *ctsio, int current_error, int sense_key,
int asc, int ascq, ...);
void ctl_sense_to_desc(struct scsi_sense_data_fixed *sense_src,
@ -60,7 +60,8 @@ void ctl_sense_to_fixed(struct scsi_sense_data_desc *sense_src,
void ctl_set_ua(struct ctl_scsiio *ctsio, int asc, int ascq);
ctl_ua_type ctl_build_qae(struct ctl_lun *lun, uint32_t initidx, uint8_t *resp);
ctl_ua_type ctl_build_ua(struct ctl_lun *lun, uint32_t initidx,
struct scsi_sense_data *sense, scsi_sense_data_type sense_format);
struct scsi_sense_data *sense, u_int *sense_len,
scsi_sense_data_type sense_format);
void ctl_set_overlapped_cmd(struct ctl_scsiio *ctsio);
void ctl_set_overlapped_tag(struct ctl_scsiio *ctsio, uint8_t tag);
void ctl_set_invalid_field(struct ctl_scsiio *ctsio, int sks_valid, int command,

View file

@ -285,7 +285,7 @@ static const struct ctl_page_index page_index_template[] = {
CTL_PAGE_FLAG_ALL, NULL, ctl_default_page_handler},
{SMS_CONTROL_MODE_PAGE | SMPH_SPF, 0x01,
sizeof(struct scsi_control_ext_page), NULL,
CTL_PAGE_FLAG_ALL, NULL, NULL},
CTL_PAGE_FLAG_ALL, NULL, ctl_default_page_handler},
{SMS_INFO_EXCEPTIONS_PAGE, 0, sizeof(struct scsi_info_exceptions_page), NULL,
CTL_PAGE_FLAG_ALL, NULL, ctl_ie_page_handler},
{SMS_INFO_EXCEPTIONS_PAGE | SMPH_SPF, 0x02,

View file

@ -3741,342 +3741,301 @@ scsi_find_desc(struct scsi_sense_data_desc *sense, u_int sense_len,
return ((uint8_t *)desc_info.header);
}
/*
* Fill in SCSI descriptor sense data with the specified parameters.
*/
static void
scsi_set_sense_data_desc_va(struct scsi_sense_data *sense_data,
u_int *sense_len, scsi_sense_data_type sense_format, int current_error,
int sense_key, int asc, int ascq, va_list ap)
{
struct scsi_sense_data_desc *sense;
scsi_sense_elem_type elem_type;
int space, len;
uint8_t *desc, *data;
memset(sense_data, 0, sizeof(*sense_data));
sense = (struct scsi_sense_data_desc *)sense_data;
if (current_error != 0)
sense->error_code = SSD_DESC_CURRENT_ERROR;
else
sense->error_code = SSD_DESC_DEFERRED_ERROR;
sense->sense_key = sense_key;
sense->add_sense_code = asc;
sense->add_sense_code_qual = ascq;
sense->flags = 0;
desc = &sense->sense_desc[0];
space = *sense_len - offsetof(struct scsi_sense_data_desc, sense_desc);
while ((elem_type = va_arg(ap, scsi_sense_elem_type)) !=
SSD_ELEM_NONE) {
if (elem_type >= SSD_ELEM_MAX) {
printf("%s: invalid sense type %d\n", __func__,
elem_type);
break;
}
len = va_arg(ap, int);
data = va_arg(ap, uint8_t *);
switch (elem_type) {
case SSD_ELEM_SKIP:
break;
case SSD_ELEM_DESC:
if (space < len) {
sense->flags |= SSDD_SDAT_OVFL;
break;
}
bcopy(data, desc, len);
desc += len;
space -= len;
break;
case SSD_ELEM_SKS: {
struct scsi_sense_sks *sks = (void *)desc;
if (len > sizeof(sks->sense_key_spec))
break;
if (space < sizeof(*sks)) {
sense->flags |= SSDD_SDAT_OVFL;
break;
}
sks->desc_type = SSD_DESC_SKS;
sks->length = sizeof(*sks) -
(offsetof(struct scsi_sense_sks, length) + 1);
bcopy(data, &sks->sense_key_spec, len);
desc += sizeof(*sks);
space -= sizeof(*sks);
break;
}
case SSD_ELEM_COMMAND: {
struct scsi_sense_command *cmd = (void *)desc;
if (len > sizeof(cmd->command_info))
break;
if (space < sizeof(*cmd)) {
sense->flags |= SSDD_SDAT_OVFL;
break;
}
cmd->desc_type = SSD_DESC_COMMAND;
cmd->length = sizeof(*cmd) -
(offsetof(struct scsi_sense_command, length) + 1);
bcopy(data, &cmd->command_info[
sizeof(cmd->command_info) - len], len);
desc += sizeof(*cmd);
space -= sizeof(*cmd);
break;
}
case SSD_ELEM_INFO: {
struct scsi_sense_info *info = (void *)desc;
if (len > sizeof(info->info))
break;
if (space < sizeof(*info)) {
sense->flags |= SSDD_SDAT_OVFL;
break;
}
info->desc_type = SSD_DESC_INFO;
info->length = sizeof(*info) -
(offsetof(struct scsi_sense_info, length) + 1);
info->byte2 = SSD_INFO_VALID;
bcopy(data, &info->info[sizeof(info->info) - len], len);
desc += sizeof(*info);
space -= sizeof(*info);
break;
}
case SSD_ELEM_FRU: {
struct scsi_sense_fru *fru = (void *)desc;
if (len > sizeof(fru->fru))
break;
if (space < sizeof(*fru)) {
sense->flags |= SSDD_SDAT_OVFL;
break;
}
fru->desc_type = SSD_DESC_FRU;
fru->length = sizeof(*fru) -
(offsetof(struct scsi_sense_fru, length) + 1);
fru->fru = *data;
desc += sizeof(*fru);
space -= sizeof(*fru);
break;
}
case SSD_ELEM_STREAM: {
struct scsi_sense_stream *stream = (void *)desc;
if (len > sizeof(stream->byte3))
break;
if (space < sizeof(*stream)) {
sense->flags |= SSDD_SDAT_OVFL;
break;
}
stream->desc_type = SSD_DESC_STREAM;
stream->length = sizeof(*stream) -
(offsetof(struct scsi_sense_stream, length) + 1);
stream->byte3 = *data;
desc += sizeof(*stream);
space -= sizeof(*stream);
break;
}
default:
/*
* We shouldn't get here, but if we do, do nothing.
* We've already consumed the arguments above.
*/
break;
}
}
sense->extra_len = desc - &sense->sense_desc[0];
*sense_len = offsetof(struct scsi_sense_data_desc, extra_len) + 1 +
sense->extra_len;
}
/*
* Fill in SCSI fixed sense data with the specified parameters.
*/
static void
scsi_set_sense_data_fixed_va(struct scsi_sense_data *sense_data,
u_int *sense_len, scsi_sense_data_type sense_format, int current_error,
int sense_key, int asc, int ascq, va_list ap)
{
struct scsi_sense_data_fixed *sense;
scsi_sense_elem_type elem_type;
uint8_t *data;
int len;
memset(sense_data, 0, sizeof(*sense_data));
sense = (struct scsi_sense_data_fixed *)sense_data;
if (current_error != 0)
sense->error_code = SSD_CURRENT_ERROR;
else
sense->error_code = SSD_DEFERRED_ERROR;
sense->flags = sense_key & SSD_KEY;
sense->extra_len = 0;
if (*sense_len >= 13) {
sense->add_sense_code = asc;
sense->extra_len = MAX(sense->extra_len, 5);
} else
sense->flags |= SSD_SDAT_OVFL;
if (*sense_len >= 14) {
sense->add_sense_code_qual = ascq;
sense->extra_len = MAX(sense->extra_len, 6);
} else
sense->flags |= SSD_SDAT_OVFL;
while ((elem_type = va_arg(ap, scsi_sense_elem_type)) !=
SSD_ELEM_NONE) {
if (elem_type >= SSD_ELEM_MAX) {
printf("%s: invalid sense type %d\n", __func__,
elem_type);
break;
}
len = va_arg(ap, int);
data = va_arg(ap, uint8_t *);
switch (elem_type) {
case SSD_ELEM_SKIP:
break;
case SSD_ELEM_SKS:
if (len > sizeof(sense->sense_key_spec))
break;
if (*sense_len < 18) {
sense->flags |= SSD_SDAT_OVFL;
break;
}
bcopy(data, &sense->sense_key_spec[0], len);
sense->extra_len = MAX(sense->extra_len, 10);
break;
case SSD_ELEM_COMMAND:
if (*sense_len < 12) {
sense->flags |= SSD_SDAT_OVFL;
break;
}
if (len > sizeof(sense->cmd_spec_info)) {
data += len - sizeof(sense->cmd_spec_info);
len -= len - sizeof(sense->cmd_spec_info);
}
bcopy(data, &sense->cmd_spec_info[
sizeof(sense->cmd_spec_info) - len], len);
sense->extra_len = MAX(sense->extra_len, 4);
break;
case SSD_ELEM_INFO:
/* Set VALID bit only if no overflow. */
sense->error_code |= SSD_ERRCODE_VALID;
while (len > sizeof(sense->info)) {
if (data[0] != 0)
sense->error_code &= ~SSD_ERRCODE_VALID;
data ++;
len --;
}
bcopy(data, &sense->info[sizeof(sense->info) - len], len);
break;
case SSD_ELEM_FRU:
if (*sense_len < 15) {
sense->flags |= SSD_SDAT_OVFL;
break;
}
sense->fru = *data;
sense->extra_len = MAX(sense->extra_len, 7);
break;
case SSD_ELEM_STREAM:
sense->flags |= *data &
(SSD_ILI | SSD_EOM | SSD_FILEMARK);
break;
default:
/*
* We can't handle that in fixed format. Skip it.
*/
break;
}
}
*sense_len = offsetof(struct scsi_sense_data_fixed, extra_len) + 1 +
sense->extra_len;
}
/*
* Fill in SCSI sense data with the specified parameters. This routine can
* fill in either fixed or descriptor type sense data.
*/
void
scsi_set_sense_data_va(struct scsi_sense_data *sense_data,
scsi_set_sense_data_va(struct scsi_sense_data *sense_data, u_int *sense_len,
scsi_sense_data_type sense_format, int current_error,
int sense_key, int asc, int ascq, va_list ap)
int sense_key, int asc, int ascq, va_list ap)
{
int descriptor_sense;
scsi_sense_elem_type elem_type;
/*
* Determine whether to return fixed or descriptor format sense
* data. If the user specifies SSD_TYPE_NONE for some reason,
* they'll just get fixed sense data.
*/
if (*sense_len > SSD_FULL_SIZE)
*sense_len = SSD_FULL_SIZE;
if (sense_format == SSD_TYPE_DESC)
descriptor_sense = 1;
scsi_set_sense_data_desc_va(sense_data, sense_len,
sense_format, current_error, sense_key, asc, ascq, ap);
else
descriptor_sense = 0;
/*
* Zero the sense data, so that we don't pass back any garbage data
* to the user.
*/
memset(sense_data, 0, sizeof(*sense_data));
if (descriptor_sense != 0) {
struct scsi_sense_data_desc *sense;
sense = (struct scsi_sense_data_desc *)sense_data;
/*
* The descriptor sense format eliminates the use of the
* valid bit.
*/
if (current_error != 0)
sense->error_code = SSD_DESC_CURRENT_ERROR;
else
sense->error_code = SSD_DESC_DEFERRED_ERROR;
sense->sense_key = sense_key;
sense->add_sense_code = asc;
sense->add_sense_code_qual = ascq;
/*
* Start off with no extra length, since the above data
* fits in the standard descriptor sense information.
*/
sense->extra_len = 0;
while ((elem_type = (scsi_sense_elem_type)va_arg(ap,
scsi_sense_elem_type)) != SSD_ELEM_NONE) {
int sense_len, len_to_copy;
uint8_t *data;
if (elem_type >= SSD_ELEM_MAX) {
printf("%s: invalid sense type %d\n", __func__,
elem_type);
break;
}
sense_len = (int)va_arg(ap, int);
len_to_copy = MIN(sense_len, SSD_EXTRA_MAX -
sense->extra_len);
data = (uint8_t *)va_arg(ap, uint8_t *);
/*
* We've already consumed the arguments for this one.
*/
if (elem_type == SSD_ELEM_SKIP)
continue;
switch (elem_type) {
case SSD_ELEM_DESC: {
/*
* This is a straight descriptor. All we
* need to do is copy the data in.
*/
bcopy(data, &sense->sense_desc[
sense->extra_len], len_to_copy);
sense->extra_len += len_to_copy;
break;
}
case SSD_ELEM_SKS: {
struct scsi_sense_sks sks;
bzero(&sks, sizeof(sks));
/*
* This is already-formatted sense key
* specific data. We just need to fill out
* the header and copy everything in.
*/
bcopy(data, &sks.sense_key_spec,
MIN(len_to_copy,
sizeof(sks.sense_key_spec)));
sks.desc_type = SSD_DESC_SKS;
sks.length = sizeof(sks) -
offsetof(struct scsi_sense_sks, reserved1);
bcopy(&sks,&sense->sense_desc[sense->extra_len],
sizeof(sks));
sense->extra_len += sizeof(sks);
break;
}
case SSD_ELEM_INFO:
case SSD_ELEM_COMMAND: {
struct scsi_sense_command cmd;
struct scsi_sense_info info;
uint8_t *data_dest;
uint8_t *descriptor;
int descriptor_size, i, copy_len;
bzero(&cmd, sizeof(cmd));
bzero(&info, sizeof(info));
/*
* Command or information data. The
* operate in pretty much the same way.
*/
if (elem_type == SSD_ELEM_COMMAND) {
len_to_copy = MIN(len_to_copy,
sizeof(cmd.command_info));
descriptor = (uint8_t *)&cmd;
descriptor_size = sizeof(cmd);
data_dest =(uint8_t *)&cmd.command_info;
cmd.desc_type = SSD_DESC_COMMAND;
cmd.length = sizeof(cmd) -
offsetof(struct scsi_sense_command,
reserved);
} else {
len_to_copy = MIN(len_to_copy,
sizeof(info.info));
descriptor = (uint8_t *)&info;
descriptor_size = sizeof(cmd);
data_dest = (uint8_t *)&info.info;
info.desc_type = SSD_DESC_INFO;
info.byte2 = SSD_INFO_VALID;
info.length = sizeof(info) -
offsetof(struct scsi_sense_info,
byte2);
}
/*
* Copy this in reverse because the spec
* (SPC-4) says that when 4 byte quantities
* are stored in this 8 byte field, the
* first four bytes shall be 0.
*
* So we fill the bytes in from the end, and
* if we have less than 8 bytes to copy,
* the initial, most significant bytes will
* be 0.
*/
for (i = sense_len - 1; i >= 0 &&
len_to_copy > 0; i--, len_to_copy--)
data_dest[len_to_copy - 1] = data[i];
/*
* This calculation looks much like the
* initial len_to_copy calculation, but
* we have to do it again here, because
* we're looking at a larger amount that
* may or may not fit. It's not only the
* data the user passed in, but also the
* rest of the descriptor.
*/
copy_len = MIN(descriptor_size,
SSD_EXTRA_MAX - sense->extra_len);
bcopy(descriptor, &sense->sense_desc[
sense->extra_len], copy_len);
sense->extra_len += copy_len;
break;
}
case SSD_ELEM_FRU: {
struct scsi_sense_fru fru;
int copy_len;
bzero(&fru, sizeof(fru));
fru.desc_type = SSD_DESC_FRU;
fru.length = sizeof(fru) -
offsetof(struct scsi_sense_fru, reserved);
fru.fru = *data;
copy_len = MIN(sizeof(fru), SSD_EXTRA_MAX -
sense->extra_len);
bcopy(&fru, &sense->sense_desc[
sense->extra_len], copy_len);
sense->extra_len += copy_len;
break;
}
case SSD_ELEM_STREAM: {
struct scsi_sense_stream stream_sense;
int copy_len;
bzero(&stream_sense, sizeof(stream_sense));
stream_sense.desc_type = SSD_DESC_STREAM;
stream_sense.length = sizeof(stream_sense) -
offsetof(struct scsi_sense_stream, reserved);
stream_sense.byte3 = *data;
copy_len = MIN(sizeof(stream_sense),
SSD_EXTRA_MAX - sense->extra_len);
bcopy(&stream_sense, &sense->sense_desc[
sense->extra_len], copy_len);
sense->extra_len += copy_len;
break;
}
default:
/*
* We shouldn't get here, but if we do, do
* nothing. We've already consumed the
* arguments above.
*/
break;
}
}
} else {
struct scsi_sense_data_fixed *sense;
sense = (struct scsi_sense_data_fixed *)sense_data;
if (current_error != 0)
sense->error_code = SSD_CURRENT_ERROR;
else
sense->error_code = SSD_DEFERRED_ERROR;
sense->flags = sense_key;
sense->add_sense_code = asc;
sense->add_sense_code_qual = ascq;
/*
* We've set the ASC and ASCQ, so we have 6 more bytes of
* valid data. If we wind up setting any of the other
* fields, we'll bump this to 10 extra bytes.
*/
sense->extra_len = 6;
while ((elem_type = (scsi_sense_elem_type)va_arg(ap,
scsi_sense_elem_type)) != SSD_ELEM_NONE) {
int sense_len, len_to_copy;
uint8_t *data;
if (elem_type >= SSD_ELEM_MAX) {
printf("%s: invalid sense type %d\n", __func__,
elem_type);
break;
}
/*
* If we get in here, just bump the extra length to
* 10 bytes. That will encompass anything we're
* going to set here.
*/
sense->extra_len = 10;
sense_len = (int)va_arg(ap, int);
data = (uint8_t *)va_arg(ap, uint8_t *);
switch (elem_type) {
case SSD_ELEM_SKS:
/*
* The user passed in pre-formatted sense
* key specific data.
*/
bcopy(data, &sense->sense_key_spec[0],
MIN(sizeof(sense->sense_key_spec),
sense_len));
break;
case SSD_ELEM_INFO:
case SSD_ELEM_COMMAND: {
uint8_t *data_dest;
int i;
if (elem_type == SSD_ELEM_COMMAND) {
data_dest = &sense->cmd_spec_info[0];
len_to_copy = MIN(sense_len,
sizeof(sense->cmd_spec_info));
} else {
data_dest = &sense->info[0];
len_to_copy = MIN(sense_len,
sizeof(sense->info));
/* Set VALID bit only if no overflow. */
for (i = 0; i < sense_len - len_to_copy;
i++) {
if (data[i] != 0)
break;
}
if (i >= sense_len - len_to_copy) {
sense->error_code |=
SSD_ERRCODE_VALID;
}
}
/*
* Copy this in reverse so that if we have
* less than 4 bytes to fill, the least
* significant bytes will be at the end.
* If we have more than 4 bytes, only the
* least significant bytes will be included.
*/
for (i = sense_len - 1; i >= 0 &&
len_to_copy > 0; i--, len_to_copy--)
data_dest[len_to_copy - 1] = data[i];
break;
}
case SSD_ELEM_FRU:
sense->fru = *data;
break;
case SSD_ELEM_STREAM:
sense->flags |= *data;
break;
case SSD_ELEM_DESC:
default:
/*
* If the user passes in descriptor sense,
* we can't handle that in fixed format.
* So just skip it, and any unknown argument
* types.
*/
break;
}
}
}
scsi_set_sense_data_fixed_va(sense_data, sense_len,
sense_format, current_error, sense_key, asc, ascq, ap);
}
void
scsi_set_sense_data(struct scsi_sense_data *sense_data,
scsi_set_sense_data(struct scsi_sense_data *sense_data,
scsi_sense_data_type sense_format, int current_error,
int sense_key, int asc, int ascq, ...)
int sense_key, int asc, int ascq, ...)
{
va_list ap;
u_int sense_len = SSD_FULL_SIZE;
va_start(ap, ascq);
scsi_set_sense_data_va(sense_data, &sense_len, sense_format,
current_error, sense_key, asc, ascq, ap);
va_end(ap);
}
void
scsi_set_sense_data_len(struct scsi_sense_data *sense_data, u_int *sense_len,
scsi_sense_data_type sense_format, int current_error,
int sense_key, int asc, int ascq, ...)
{
va_list ap;
va_start(ap, ascq);
scsi_set_sense_data_va(sense_data, sense_format, current_error,
sense_key, asc, ascq, ap);
scsi_set_sense_data_va(sense_data, sense_len, sense_format,
current_error, sense_key, asc, ascq, ap);
va_end(ap);
}

View file

@ -3196,11 +3196,12 @@ struct scsi_sense_data_fixed
#define SSD_KEY_BLANK_CHECK 0x08
#define SSD_KEY_Vendor_Specific 0x09
#define SSD_KEY_COPY_ABORTED 0x0a
#define SSD_KEY_ABORTED_COMMAND 0x0b
#define SSD_KEY_ABORTED_COMMAND 0x0b
#define SSD_KEY_EQUAL 0x0c
#define SSD_KEY_VOLUME_OVERFLOW 0x0d
#define SSD_KEY_MISCOMPARE 0x0e
#define SSD_KEY_COMPLETED 0x0f
#define SSD_KEY_COMPLETED 0x0f
#define SSD_SDAT_OVFL 0x10
#define SSD_ILI 0x20
#define SSD_EOM 0x40
#define SSD_FILEMARK 0x80
@ -3238,7 +3239,9 @@ struct scsi_sense_data_desc
uint8_t sense_key;
uint8_t add_sense_code;
uint8_t add_sense_code_qual;
uint8_t reserved[3];
uint8_t flags;
#define SSDD_SDAT_OVFL 0x80
uint8_t reserved[2];
/*
* Note that SPC-4, section 4.5.2.1 says that the extra_len field
* must be less than or equal to 244.
@ -3706,13 +3709,15 @@ void scsi_desc_iterate(struct scsi_sense_data_desc *sense, u_int sense_len,
void *), void *arg);
uint8_t *scsi_find_desc(struct scsi_sense_data_desc *sense, u_int sense_len,
uint8_t desc_type);
void scsi_set_sense_data(struct scsi_sense_data *sense_data,
void scsi_set_sense_data(struct scsi_sense_data *sense_data,
scsi_sense_data_type sense_format, int current_error,
int sense_key, int asc, int ascq, ...) ;
void scsi_set_sense_data_len(struct scsi_sense_data *sense_data,
u_int *sense_len, scsi_sense_data_type sense_format, int current_error,
int sense_key, int asc, int ascq, ...) ;
void scsi_set_sense_data_va(struct scsi_sense_data *sense_data,
scsi_sense_data_type sense_format,
int current_error, int sense_key, int asc,
int ascq, va_list ap);
u_int *sense_len, scsi_sense_data_type sense_format,
int current_error, int sense_key, int asc, int ascq, va_list ap);
int scsi_get_sense_info(struct scsi_sense_data *sense_data, u_int sense_len,
uint8_t info_type, uint64_t *info,
int64_t *signed_info);