linux/drivers/scsi/scsi_common.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * SCSI functions used by both the initiator and the target code.
   4 */
   5
   6#include <linux/bug.h>
   7#include <linux/kernel.h>
   8#include <linux/string.h>
   9#include <linux/errno.h>
  10#include <asm/unaligned.h>
  11#include <scsi/scsi_common.h>
  12
  13/* NB: These are exposed through /proc/scsi/scsi and form part of the ABI.
  14 * You may not alter any existing entry (although adding new ones is
  15 * encouraged once assigned by ANSI/INCITS T10).
  16 */
  17static const char *const scsi_device_types[] = {
  18        "Direct-Access    ",
  19        "Sequential-Access",
  20        "Printer          ",
  21        "Processor        ",
  22        "WORM             ",
  23        "CD-ROM           ",
  24        "Scanner          ",
  25        "Optical Device   ",
  26        "Medium Changer   ",
  27        "Communications   ",
  28        "ASC IT8          ",
  29        "ASC IT8          ",
  30        "RAID             ",
  31        "Enclosure        ",
  32        "Direct-Access-RBC",
  33        "Optical card     ",
  34        "Bridge controller",
  35        "Object storage   ",
  36        "Automation/Drive ",
  37        "Security Manager ",
  38        "Direct-Access-ZBC",
  39};
  40
  41/**
  42 * scsi_device_type - Return 17-char string indicating device type.
  43 * @type: type number to look up
  44 */
  45const char *scsi_device_type(unsigned type)
  46{
  47        if (type == 0x1e)
  48                return "Well-known LUN   ";
  49        if (type == 0x1f)
  50                return "No Device        ";
  51        if (type >= ARRAY_SIZE(scsi_device_types))
  52                return "Unknown          ";
  53        return scsi_device_types[type];
  54}
  55EXPORT_SYMBOL(scsi_device_type);
  56
  57/**
  58 * scsilun_to_int - convert a scsi_lun to an int
  59 * @scsilun:    struct scsi_lun to be converted.
  60 *
  61 * Description:
  62 *     Convert @scsilun from a struct scsi_lun to a four-byte host byte-ordered
  63 *     integer, and return the result. The caller must check for
  64 *     truncation before using this function.
  65 *
  66 * Notes:
  67 *     For a description of the LUN format, post SCSI-3 see the SCSI
  68 *     Architecture Model, for SCSI-3 see the SCSI Controller Commands.
  69 *
  70 *     Given a struct scsi_lun of: d2 04 0b 03 00 00 00 00, this function
  71 *     returns the integer: 0x0b03d204
  72 *
  73 *     This encoding will return a standard integer LUN for LUNs smaller
  74 *     than 256, which typically use a single level LUN structure with
  75 *     addressing method 0.
  76 */
  77u64 scsilun_to_int(struct scsi_lun *scsilun)
  78{
  79        int i;
  80        u64 lun;
  81
  82        lun = 0;
  83        for (i = 0; i < sizeof(lun); i += 2)
  84                lun = lun | (((u64)scsilun->scsi_lun[i] << ((i + 1) * 8)) |
  85                             ((u64)scsilun->scsi_lun[i + 1] << (i * 8)));
  86        return lun;
  87}
  88EXPORT_SYMBOL(scsilun_to_int);
  89
  90/**
  91 * int_to_scsilun - reverts an int into a scsi_lun
  92 * @lun:        integer to be reverted
  93 * @scsilun:    struct scsi_lun to be set.
  94 *
  95 * Description:
  96 *     Reverts the functionality of the scsilun_to_int, which packed
  97 *     an 8-byte lun value into an int. This routine unpacks the int
  98 *     back into the lun value.
  99 *
 100 * Notes:
 101 *     Given an integer : 0x0b03d204, this function returns a
 102 *     struct scsi_lun of: d2 04 0b 03 00 00 00 00
 103 *
 104 */
 105void int_to_scsilun(u64 lun, struct scsi_lun *scsilun)
 106{
 107        int i;
 108
 109        memset(scsilun->scsi_lun, 0, sizeof(scsilun->scsi_lun));
 110
 111        for (i = 0; i < sizeof(lun); i += 2) {
 112                scsilun->scsi_lun[i] = (lun >> 8) & 0xFF;
 113                scsilun->scsi_lun[i+1] = lun & 0xFF;
 114                lun = lun >> 16;
 115        }
 116}
 117EXPORT_SYMBOL(int_to_scsilun);
 118
 119/**
 120 * scsi_normalize_sense - normalize main elements from either fixed or
 121 *                      descriptor sense data format into a common format.
 122 *
 123 * @sense_buffer:       byte array containing sense data returned by device
 124 * @sb_len:             number of valid bytes in sense_buffer
 125 * @sshdr:              pointer to instance of structure that common
 126 *                      elements are written to.
 127 *
 128 * Notes:
 129 *      The "main elements" from sense data are: response_code, sense_key,
 130 *      asc, ascq and additional_length (only for descriptor format).
 131 *
 132 *      Typically this function can be called after a device has
 133 *      responded to a SCSI command with the CHECK_CONDITION status.
 134 *
 135 * Return value:
 136 *      true if valid sense data information found, else false;
 137 */
 138bool scsi_normalize_sense(const u8 *sense_buffer, int sb_len,
 139                          struct scsi_sense_hdr *sshdr)
 140{
 141        memset(sshdr, 0, sizeof(struct scsi_sense_hdr));
 142
 143        if (!sense_buffer || !sb_len)
 144                return false;
 145
 146        sshdr->response_code = (sense_buffer[0] & 0x7f);
 147
 148        if (!scsi_sense_valid(sshdr))
 149                return false;
 150
 151        if (sshdr->response_code >= 0x72) {
 152                /*
 153                 * descriptor format
 154                 */
 155                if (sb_len > 1)
 156                        sshdr->sense_key = (sense_buffer[1] & 0xf);
 157                if (sb_len > 2)
 158                        sshdr->asc = sense_buffer[2];
 159                if (sb_len > 3)
 160                        sshdr->ascq = sense_buffer[3];
 161                if (sb_len > 7)
 162                        sshdr->additional_length = sense_buffer[7];
 163        } else {
 164                /*
 165                 * fixed format
 166                 */
 167                if (sb_len > 2)
 168                        sshdr->sense_key = (sense_buffer[2] & 0xf);
 169                if (sb_len > 7) {
 170                        sb_len = (sb_len < (sense_buffer[7] + 8)) ?
 171                                         sb_len : (sense_buffer[7] + 8);
 172                        if (sb_len > 12)
 173                                sshdr->asc = sense_buffer[12];
 174                        if (sb_len > 13)
 175                                sshdr->ascq = sense_buffer[13];
 176                }
 177        }
 178
 179        return true;
 180}
 181EXPORT_SYMBOL(scsi_normalize_sense);
 182
 183/**
 184 * scsi_sense_desc_find - search for a given descriptor type in descriptor sense data format.
 185 * @sense_buffer:       byte array of descriptor format sense data
 186 * @sb_len:             number of valid bytes in sense_buffer
 187 * @desc_type:          value of descriptor type to find
 188 *                      (e.g. 0 -> information)
 189 *
 190 * Notes:
 191 *      only valid when sense data is in descriptor format
 192 *
 193 * Return value:
 194 *      pointer to start of (first) descriptor if found else NULL
 195 */
 196const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len,
 197                                int desc_type)
 198{
 199        int add_sen_len, add_len, desc_len, k;
 200        const u8 * descp;
 201
 202        if ((sb_len < 8) || (0 == (add_sen_len = sense_buffer[7])))
 203                return NULL;
 204        if ((sense_buffer[0] < 0x72) || (sense_buffer[0] > 0x73))
 205                return NULL;
 206        add_sen_len = (add_sen_len < (sb_len - 8)) ?
 207                        add_sen_len : (sb_len - 8);
 208        descp = &sense_buffer[8];
 209        for (desc_len = 0, k = 0; k < add_sen_len; k += desc_len) {
 210                descp += desc_len;
 211                add_len = (k < (add_sen_len - 1)) ? descp[1]: -1;
 212                desc_len = add_len + 2;
 213                if (descp[0] == desc_type)
 214                        return descp;
 215                if (add_len < 0) // short descriptor ??
 216                        break;
 217        }
 218        return NULL;
 219}
 220EXPORT_SYMBOL(scsi_sense_desc_find);
 221
 222/**
 223 * scsi_build_sense_buffer - build sense data in a buffer
 224 * @desc:       Sense format (non-zero == descriptor format,
 225 *              0 == fixed format)
 226 * @buf:        Where to build sense data
 227 * @key:        Sense key
 228 * @asc:        Additional sense code
 229 * @ascq:       Additional sense code qualifier
 230 *
 231 **/
 232void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq)
 233{
 234        if (desc) {
 235                buf[0] = 0x72;  /* descriptor, current */
 236                buf[1] = key;
 237                buf[2] = asc;
 238                buf[3] = ascq;
 239                buf[7] = 0;
 240        } else {
 241                buf[0] = 0x70;  /* fixed, current */
 242                buf[2] = key;
 243                buf[7] = 0xa;
 244                buf[12] = asc;
 245                buf[13] = ascq;
 246        }
 247}
 248EXPORT_SYMBOL(scsi_build_sense_buffer);
 249
 250/**
 251 * scsi_set_sense_information - set the information field in a
 252 *              formatted sense data buffer
 253 * @buf:        Where to build sense data
 254 * @buf_len:    buffer length
 255 * @info:       64-bit information value to be set
 256 *
 257 * Return value:
 258 *      0 on success or -EINVAL for invalid sense buffer length
 259 **/
 260int scsi_set_sense_information(u8 *buf, int buf_len, u64 info)
 261{
 262        if ((buf[0] & 0x7f) == 0x72) {
 263                u8 *ucp, len;
 264
 265                len = buf[7];
 266                ucp = (char *)scsi_sense_desc_find(buf, len + 8, 0);
 267                if (!ucp) {
 268                        buf[7] = len + 0xc;
 269                        ucp = buf + 8 + len;
 270                }
 271
 272                if (buf_len < len + 0xc)
 273                        /* Not enough room for info */
 274                        return -EINVAL;
 275
 276                ucp[0] = 0;
 277                ucp[1] = 0xa;
 278                ucp[2] = 0x80; /* Valid bit */
 279                ucp[3] = 0;
 280                put_unaligned_be64(info, &ucp[4]);
 281        } else if ((buf[0] & 0x7f) == 0x70) {
 282                /*
 283                 * Only set the 'VALID' bit if we can represent the value
 284                 * correctly; otherwise just fill out the lower bytes and
 285                 * clear the 'VALID' flag.
 286                 */
 287                if (info <= 0xffffffffUL)
 288                        buf[0] |= 0x80;
 289                else
 290                        buf[0] &= 0x7f;
 291                put_unaligned_be32((u32)info, &buf[3]);
 292        }
 293
 294        return 0;
 295}
 296EXPORT_SYMBOL(scsi_set_sense_information);
 297
 298/**
 299 * scsi_set_sense_field_pointer - set the field pointer sense key
 300 *              specific information in a formatted sense data buffer
 301 * @buf:        Where to build sense data
 302 * @buf_len:    buffer length
 303 * @fp:         field pointer to be set
 304 * @bp:         bit pointer to be set
 305 * @cd:         command/data bit
 306 *
 307 * Return value:
 308 *      0 on success or -EINVAL for invalid sense buffer length
 309 */
 310int scsi_set_sense_field_pointer(u8 *buf, int buf_len, u16 fp, u8 bp, bool cd)
 311{
 312        u8 *ucp, len;
 313
 314        if ((buf[0] & 0x7f) == 0x72) {
 315                len = buf[7];
 316                ucp = (char *)scsi_sense_desc_find(buf, len + 8, 2);
 317                if (!ucp) {
 318                        buf[7] = len + 8;
 319                        ucp = buf + 8 + len;
 320                }
 321
 322                if (buf_len < len + 8)
 323                        /* Not enough room for info */
 324                        return -EINVAL;
 325
 326                ucp[0] = 2;
 327                ucp[1] = 6;
 328                ucp[4] = 0x80; /* Valid bit */
 329                if (cd)
 330                        ucp[4] |= 0x40;
 331                if (bp < 0x8)
 332                        ucp[4] |= 0x8 | bp;
 333                put_unaligned_be16(fp, &ucp[5]);
 334        } else if ((buf[0] & 0x7f) == 0x70) {
 335                len = buf[7];
 336                if (len < 18)
 337                        buf[7] = 18;
 338
 339                buf[15] = 0x80;
 340                if (cd)
 341                        buf[15] |= 0x40;
 342                if (bp < 0x8)
 343                        buf[15] |= 0x8 | bp;
 344                put_unaligned_be16(fp, &buf[16]);
 345        }
 346
 347        return 0;
 348}
 349EXPORT_SYMBOL(scsi_set_sense_field_pointer);
 350