LCOV - code coverage report
Current view: top level - drivers/scsi - scsi_common.c (source / functions) Hit Total Coverage
Test: landlock.info Lines: 0 116 0.0 %
Date: 2021-04-22 12:43:58 Functions: 0 8 0.0 %

          Line data    Source code
       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             :  */
      17             : static 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             :  */
      45           0 : const char *scsi_device_type(unsigned type)
      46             : {
      47           0 :         if (type == 0x1e)
      48             :                 return "Well-known LUN   ";
      49           0 :         if (type == 0x1f)
      50             :                 return "No Device        ";
      51           0 :         if (type >= ARRAY_SIZE(scsi_device_types))
      52             :                 return "Unknown          ";
      53           0 :         return scsi_device_types[type];
      54             : }
      55             : EXPORT_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             :  */
      77           0 : u64 scsilun_to_int(struct scsi_lun *scsilun)
      78             : {
      79           0 :         int i;
      80           0 :         u64 lun;
      81             : 
      82           0 :         lun = 0;
      83           0 :         for (i = 0; i < sizeof(lun); i += 2)
      84           0 :                 lun = lun | (((u64)scsilun->scsi_lun[i] << ((i + 1) * 8)) |
      85           0 :                              ((u64)scsilun->scsi_lun[i + 1] << (i * 8)));
      86           0 :         return lun;
      87             : }
      88             : EXPORT_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             :  */
     105           0 : void int_to_scsilun(u64 lun, struct scsi_lun *scsilun)
     106             : {
     107           0 :         int i;
     108             : 
     109           0 :         memset(scsilun->scsi_lun, 0, sizeof(scsilun->scsi_lun));
     110             : 
     111           0 :         for (i = 0; i < sizeof(lun); i += 2) {
     112           0 :                 scsilun->scsi_lun[i] = (lun >> 8) & 0xFF;
     113           0 :                 scsilun->scsi_lun[i+1] = lun & 0xFF;
     114           0 :                 lun = lun >> 16;
     115             :         }
     116           0 : }
     117             : EXPORT_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             :  */
     138           0 : bool scsi_normalize_sense(const u8 *sense_buffer, int sb_len,
     139             :                           struct scsi_sense_hdr *sshdr)
     140             : {
     141           0 :         memset(sshdr, 0, sizeof(struct scsi_sense_hdr));
     142             : 
     143           0 :         if (!sense_buffer || !sb_len)
     144             :                 return false;
     145             : 
     146           0 :         sshdr->response_code = (sense_buffer[0] & 0x7f);
     147             : 
     148           0 :         if (!scsi_sense_valid(sshdr))
     149             :                 return false;
     150             : 
     151           0 :         if (sshdr->response_code >= 0x72) {
     152             :                 /*
     153             :                  * descriptor format
     154             :                  */
     155           0 :                 if (sb_len > 1)
     156           0 :                         sshdr->sense_key = (sense_buffer[1] & 0xf);
     157           0 :                 if (sb_len > 2)
     158           0 :                         sshdr->asc = sense_buffer[2];
     159           0 :                 if (sb_len > 3)
     160           0 :                         sshdr->ascq = sense_buffer[3];
     161           0 :                 if (sb_len > 7)
     162           0 :                         sshdr->additional_length = sense_buffer[7];
     163             :         } else {
     164             :                 /*
     165             :                  * fixed format
     166             :                  */
     167           0 :                 if (sb_len > 2)
     168           0 :                         sshdr->sense_key = (sense_buffer[2] & 0xf);
     169           0 :                 if (sb_len > 7) {
     170           0 :                         sb_len = (sb_len < (sense_buffer[7] + 8)) ?
     171             :                                          sb_len : (sense_buffer[7] + 8);
     172           0 :                         if (sb_len > 12)
     173           0 :                                 sshdr->asc = sense_buffer[12];
     174           0 :                         if (sb_len > 13)
     175           0 :                                 sshdr->ascq = sense_buffer[13];
     176             :                 }
     177             :         }
     178             : 
     179             :         return true;
     180             : }
     181             : EXPORT_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             :  */
     196           0 : const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len,
     197             :                                 int desc_type)
     198             : {
     199           0 :         int add_sen_len, add_len, desc_len, k;
     200           0 :         const u8 * descp;
     201             : 
     202           0 :         if ((sb_len < 8) || (0 == (add_sen_len = sense_buffer[7])))
     203             :                 return NULL;
     204           0 :         if ((sense_buffer[0] < 0x72) || (sense_buffer[0] > 0x73))
     205             :                 return NULL;
     206           0 :         add_sen_len = (add_sen_len < (sb_len - 8)) ?
     207             :                         add_sen_len : (sb_len - 8);
     208           0 :         descp = &sense_buffer[8];
     209           0 :         for (desc_len = 0, k = 0; k < add_sen_len; k += desc_len) {
     210           0 :                 descp += desc_len;
     211           0 :                 add_len = (k < (add_sen_len - 1)) ? descp[1]: -1;
     212           0 :                 desc_len = add_len + 2;
     213           0 :                 if (descp[0] == desc_type)
     214           0 :                         return descp;
     215           0 :                 if (add_len < 0) // short descriptor ??
     216             :                         break;
     217             :         }
     218             :         return NULL;
     219             : }
     220             : EXPORT_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             :  **/
     232           0 : void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq)
     233             : {
     234           0 :         if (desc) {
     235           0 :                 buf[0] = 0x72;  /* descriptor, current */
     236           0 :                 buf[1] = key;
     237           0 :                 buf[2] = asc;
     238           0 :                 buf[3] = ascq;
     239           0 :                 buf[7] = 0;
     240             :         } else {
     241           0 :                 buf[0] = 0x70;  /* fixed, current */
     242           0 :                 buf[2] = key;
     243           0 :                 buf[7] = 0xa;
     244           0 :                 buf[12] = asc;
     245           0 :                 buf[13] = ascq;
     246             :         }
     247           0 : }
     248             : EXPORT_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             :  **/
     260           0 : int scsi_set_sense_information(u8 *buf, int buf_len, u64 info)
     261             : {
     262           0 :         if ((buf[0] & 0x7f) == 0x72) {
     263           0 :                 u8 *ucp, len;
     264             : 
     265           0 :                 len = buf[7];
     266           0 :                 ucp = (char *)scsi_sense_desc_find(buf, len + 8, 0);
     267           0 :                 if (!ucp) {
     268           0 :                         buf[7] = len + 0xc;
     269           0 :                         ucp = buf + 8 + len;
     270             :                 }
     271             : 
     272           0 :                 if (buf_len < len + 0xc)
     273             :                         /* Not enough room for info */
     274             :                         return -EINVAL;
     275             : 
     276           0 :                 ucp[0] = 0;
     277           0 :                 ucp[1] = 0xa;
     278           0 :                 ucp[2] = 0x80; /* Valid bit */
     279           0 :                 ucp[3] = 0;
     280           0 :                 put_unaligned_be64(info, &ucp[4]);
     281           0 :         } 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           0 :                 if (info <= 0xffffffffUL)
     288           0 :                         buf[0] |= 0x80;
     289             :                 else
     290           0 :                         buf[0] &= 0x7f;
     291           0 :                 put_unaligned_be32((u32)info, &buf[3]);
     292             :         }
     293             : 
     294             :         return 0;
     295             : }
     296             : EXPORT_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             :  */
     310           0 : int scsi_set_sense_field_pointer(u8 *buf, int buf_len, u16 fp, u8 bp, bool cd)
     311             : {
     312           0 :         u8 *ucp, len;
     313             : 
     314           0 :         if ((buf[0] & 0x7f) == 0x72) {
     315           0 :                 len = buf[7];
     316           0 :                 ucp = (char *)scsi_sense_desc_find(buf, len + 8, 2);
     317           0 :                 if (!ucp) {
     318           0 :                         buf[7] = len + 8;
     319           0 :                         ucp = buf + 8 + len;
     320             :                 }
     321             : 
     322           0 :                 if (buf_len < len + 8)
     323             :                         /* Not enough room for info */
     324             :                         return -EINVAL;
     325             : 
     326           0 :                 ucp[0] = 2;
     327           0 :                 ucp[1] = 6;
     328           0 :                 ucp[4] = 0x80; /* Valid bit */
     329           0 :                 if (cd)
     330           0 :                         ucp[4] |= 0x40;
     331           0 :                 if (bp < 0x8)
     332           0 :                         ucp[4] |= 0x8 | bp;
     333           0 :                 put_unaligned_be16(fp, &ucp[5]);
     334           0 :         } else if ((buf[0] & 0x7f) == 0x70) {
     335           0 :                 len = buf[7];
     336           0 :                 if (len < 18)
     337           0 :                         buf[7] = 18;
     338             : 
     339           0 :                 buf[15] = 0x80;
     340           0 :                 if (cd)
     341           0 :                         buf[15] |= 0x40;
     342           0 :                 if (bp < 0x8)
     343           0 :                         buf[15] |= 0x8 | bp;
     344           0 :                 put_unaligned_be16(fp, &buf[16]);
     345             :         }
     346             : 
     347             :         return 0;
     348             : }
     349             : EXPORT_SYMBOL(scsi_set_sense_field_pointer);

Generated by: LCOV version 1.14