LCOV - code coverage report
Current view: top level - udev/scsi_id - scsi_serial.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 0 372 0.0 %
Date: 2019-08-23 13:36:53 Functions: 0 16 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 323 0.0 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: GPL-2.0+ */
       2                 :            : /*
       3                 :            :  * Copyright © IBM Corp. 2003
       4                 :            :  *
       5                 :            :  * Author: Patrick Mansfield<patmans@us.ibm.com>
       6                 :            :  */
       7                 :            : 
       8                 :            : #include <errno.h>
       9                 :            : #include <fcntl.h>
      10                 :            : #include <inttypes.h>
      11                 :            : #include <linux/bsg.h>
      12                 :            : #include <linux/types.h>
      13                 :            : #include <scsi/scsi.h>
      14                 :            : #include <scsi/sg.h>
      15                 :            : #include <stdio.h>
      16                 :            : #include <stdlib.h>
      17                 :            : #include <string.h>
      18                 :            : #include <sys/ioctl.h>
      19                 :            : #include <sys/stat.h>
      20                 :            : #include <sys/types.h>
      21                 :            : #include <time.h>
      22                 :            : #include <unistd.h>
      23                 :            : 
      24                 :            : #include "memory-util.h"
      25                 :            : #include "random-util.h"
      26                 :            : #include "scsi.h"
      27                 :            : #include "scsi_id.h"
      28                 :            : #include "string-util.h"
      29                 :            : 
      30                 :            : /*
      31                 :            :  * A priority based list of id, naa, and binary/ascii for the identifier
      32                 :            :  * descriptor in VPD page 0x83.
      33                 :            :  *
      34                 :            :  * Brute force search for a match starting with the first value in the
      35                 :            :  * following id_search_list. This is not a performance issue, since there
      36                 :            :  * is normally one or some small number of descriptors.
      37                 :            :  */
      38                 :            : static const struct scsi_id_search_values id_search_list[] = {
      39                 :            :         { SCSI_ID_TGTGROUP, SCSI_ID_NAA_DONT_CARE,         SCSI_ID_BINARY },
      40                 :            :         { SCSI_ID_NAA,      SCSI_ID_NAA_IEEE_REG_EXTENDED, SCSI_ID_BINARY },
      41                 :            :         { SCSI_ID_NAA,      SCSI_ID_NAA_IEEE_REG_EXTENDED, SCSI_ID_ASCII  },
      42                 :            :         { SCSI_ID_NAA,      SCSI_ID_NAA_IEEE_REG,          SCSI_ID_BINARY },
      43                 :            :         { SCSI_ID_NAA,      SCSI_ID_NAA_IEEE_REG,          SCSI_ID_ASCII  },
      44                 :            :         /*
      45                 :            :          * Devices already exist using NAA values that are now marked
      46                 :            :          * reserved. These should not conflict with other values, or it is
      47                 :            :          * a bug in the device. As long as we find the IEEE extended one
      48                 :            :          * first, we really don't care what other ones are used. Using
      49                 :            :          * don't care here means that a device that returns multiple
      50                 :            :          * non-IEEE descriptors in a random order will get different
      51                 :            :          * names.
      52                 :            :          */
      53                 :            :         { SCSI_ID_NAA,             SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY },
      54                 :            :         { SCSI_ID_NAA,             SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII  },
      55                 :            :         { SCSI_ID_EUI_64,          SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY },
      56                 :            :         { SCSI_ID_EUI_64,          SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII  },
      57                 :            :         { SCSI_ID_T10_VENDOR,      SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY },
      58                 :            :         { SCSI_ID_T10_VENDOR,      SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII  },
      59                 :            :         { SCSI_ID_VENDOR_SPECIFIC, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY },
      60                 :            :         { SCSI_ID_VENDOR_SPECIFIC, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII  },
      61                 :            : };
      62                 :            : 
      63                 :            : static const char hex_str[]="0123456789abcdef";
      64                 :            : 
      65                 :            : /*
      66                 :            :  * Values returned in the result/status, only the ones used by the code
      67                 :            :  * are used here.
      68                 :            :  */
      69                 :            : 
      70                 :            : #define DID_NO_CONNECT               0x01        /* Unable to connect before timeout */
      71                 :            : #define DID_BUS_BUSY                 0x02        /* Bus remain busy until timeout */
      72                 :            : #define DID_TIME_OUT                 0x03        /* Timed out for some other reason */
      73                 :            : #define DRIVER_TIMEOUT               0x06
      74                 :            : #define DRIVER_SENSE                 0x08        /* Sense_buffer has been set */
      75                 :            : 
      76                 :            : /* The following "category" function returns one of the following */
      77                 :            : #define SG_ERR_CAT_CLEAN                0        /* No errors or other information */
      78                 :            : #define SG_ERR_CAT_MEDIA_CHANGED        1        /* interpreted from sense buffer */
      79                 :            : #define SG_ERR_CAT_RESET                2        /* interpreted from sense buffer */
      80                 :            : #define SG_ERR_CAT_TIMEOUT              3
      81                 :            : #define SG_ERR_CAT_RECOVERED            4        /* Successful command after recovered err */
      82                 :            : #define SG_ERR_CAT_NOTSUPPORTED         5        /* Illegal / unsupported command */
      83                 :            : #define SG_ERR_CAT_SENSE               98        /* Something else in the sense buffer */
      84                 :            : #define SG_ERR_CAT_OTHER               99        /* Some other error/warning */
      85                 :            : 
      86                 :            : static int do_scsi_page80_inquiry(struct scsi_id_device *dev_scsi, int fd,
      87                 :            :                                   char *serial, char *serial_short, int max_len);
      88                 :            : 
      89                 :          0 : static int sg_err_category_new(int scsi_status, int msg_status, int
      90                 :            :                                host_status, int driver_status, const
      91                 :            :                                unsigned char *sense_buffer, int sb_len) {
      92                 :          0 :         scsi_status &= 0x7e;
      93                 :            : 
      94                 :            :         /*
      95                 :            :          * XXX change to return only two values - failed or OK.
      96                 :            :          */
      97                 :            : 
      98   [ #  #  #  #  :          0 :         if (!scsi_status && !host_status && !driver_status)
                   #  # ]
      99                 :          0 :                 return SG_ERR_CAT_CLEAN;
     100                 :            : 
     101   [ #  #  #  # ]:          0 :         if (IN_SET(scsi_status, SCSI_CHECK_CONDITION, SCSI_COMMAND_TERMINATED) ||
     102         [ #  # ]:          0 :             (driver_status & 0xf) == DRIVER_SENSE) {
     103   [ #  #  #  # ]:          0 :                 if (sense_buffer && (sb_len > 2)) {
     104                 :            :                         int sense_key;
     105                 :            :                         unsigned char asc;
     106                 :            : 
     107         [ #  # ]:          0 :                         if (sense_buffer[0] & 0x2) {
     108                 :          0 :                                 sense_key = sense_buffer[1] & 0xf;
     109                 :          0 :                                 asc = sense_buffer[2];
     110                 :            :                         } else {
     111                 :          0 :                                 sense_key = sense_buffer[2] & 0xf;
     112         [ #  # ]:          0 :                                 asc = (sb_len > 12) ? sense_buffer[12] : 0;
     113                 :            :                         }
     114                 :            : 
     115         [ #  # ]:          0 :                         if (sense_key == RECOVERED_ERROR)
     116                 :          0 :                                 return SG_ERR_CAT_RECOVERED;
     117         [ #  # ]:          0 :                         else if (sense_key == UNIT_ATTENTION) {
     118         [ #  # ]:          0 :                                 if (0x28 == asc)
     119                 :          0 :                                         return SG_ERR_CAT_MEDIA_CHANGED;
     120         [ #  # ]:          0 :                                 if (0x29 == asc)
     121                 :          0 :                                         return SG_ERR_CAT_RESET;
     122         [ #  # ]:          0 :                         } else if (sense_key == ILLEGAL_REQUEST)
     123                 :          0 :                                 return SG_ERR_CAT_NOTSUPPORTED;
     124                 :            :                 }
     125                 :          0 :                 return SG_ERR_CAT_SENSE;
     126                 :            :         }
     127         [ #  # ]:          0 :         if (host_status) {
     128   [ #  #  #  # ]:          0 :                 if (IN_SET(host_status, DID_NO_CONNECT, DID_BUS_BUSY, DID_TIME_OUT))
     129                 :          0 :                         return SG_ERR_CAT_TIMEOUT;
     130                 :            :         }
     131         [ #  # ]:          0 :         if (driver_status) {
     132         [ #  # ]:          0 :                 if (driver_status == DRIVER_TIMEOUT)
     133                 :          0 :                         return SG_ERR_CAT_TIMEOUT;
     134                 :            :         }
     135                 :          0 :         return SG_ERR_CAT_OTHER;
     136                 :            : }
     137                 :            : 
     138                 :          0 : static int sg_err_category3(struct sg_io_hdr *hp) {
     139                 :          0 :         return sg_err_category_new(hp->status, hp->msg_status,
     140                 :          0 :                                    hp->host_status, hp->driver_status,
     141                 :          0 :                                    hp->sbp, hp->sb_len_wr);
     142                 :            : }
     143                 :            : 
     144                 :          0 : static int sg_err_category4(struct sg_io_v4 *hp) {
     145                 :          0 :         return sg_err_category_new(hp->device_status, 0,
     146                 :          0 :                                    hp->transport_status, hp->driver_status,
     147                 :          0 :                                    (unsigned char *)(uintptr_t)hp->response,
     148                 :          0 :                                    hp->response_len);
     149                 :            : }
     150                 :            : 
     151                 :          0 : static int scsi_dump_sense(struct scsi_id_device *dev_scsi,
     152                 :            :                            unsigned char *sense_buffer, int sb_len) {
     153                 :            :         int s;
     154                 :            :         int code;
     155                 :            :         int sense_class;
     156                 :            :         int sense_key;
     157                 :            :         int asc, ascq;
     158                 :            : 
     159                 :            :         /*
     160                 :            :          * Figure out and print the sense key, asc and ascq.
     161                 :            :          *
     162                 :            :          * If you want to suppress these for a particular drive model, add
     163                 :            :          * a black list entry in the scsi_id config file.
     164                 :            :          *
     165                 :            :          * XXX We probably need to: lookup the sense/asc/ascq in a retry
     166                 :            :          * table, and if found return 1 (after dumping the sense, asc, and
     167                 :            :          * ascq). So, if/when we get something like a power on/reset,
     168                 :            :          * we'll retry the command.
     169                 :            :          */
     170                 :            : 
     171         [ #  # ]:          0 :         if (sb_len < 1)
     172         [ #  # ]:          0 :                 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
     173                 :            :                                        "%s: sense buffer empty",
     174                 :            :                                        dev_scsi->kernel);
     175                 :            : 
     176                 :          0 :         sense_class = (sense_buffer[0] >> 4) & 0x07;
     177                 :          0 :         code = sense_buffer[0] & 0xf;
     178                 :            : 
     179         [ #  # ]:          0 :         if (sense_class == 7) {
     180                 :            :                 /*
     181                 :            :                  * extended sense data.
     182                 :            :                  */
     183                 :          0 :                 s = sense_buffer[7] + 8;
     184         [ #  # ]:          0 :                 if (sb_len < s)
     185         [ #  # ]:          0 :                         return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
     186                 :            :                                                "%s: sense buffer too small %d bytes, %d bytes too short",
     187                 :            :                                                dev_scsi->kernel, sb_len,
     188                 :            :                                                s - sb_len);
     189                 :            : 
     190   [ #  #  #  # ]:          0 :                 if (IN_SET(code, 0x0, 0x1)) {
     191                 :          0 :                         sense_key = sense_buffer[2] & 0xf;
     192         [ #  # ]:          0 :                         if (s < 14)
     193                 :            :                                 /*
     194                 :            :                                  * Possible?
     195                 :            :                                  */
     196         [ #  # ]:          0 :                                 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
     197                 :            :                                                        "%s: sense result too small %d bytes",
     198                 :            :                                                        dev_scsi->kernel, s);
     199                 :            : 
     200                 :          0 :                         asc = sense_buffer[12];
     201                 :          0 :                         ascq = sense_buffer[13];
     202   [ #  #  #  # ]:          0 :                 } else if (IN_SET(code, 0x2, 0x3)) {
     203                 :          0 :                         sense_key = sense_buffer[1] & 0xf;
     204                 :          0 :                         asc = sense_buffer[2];
     205                 :          0 :                         ascq = sense_buffer[3];
     206                 :            :                 } else
     207         [ #  # ]:          0 :                         return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
     208                 :            :                                                "%s: invalid sense code 0x%x",
     209                 :            :                                                dev_scsi->kernel, code);
     210                 :            : 
     211         [ #  # ]:          0 :                 log_debug("%s: sense key 0x%x ASC 0x%x ASCQ 0x%x",
     212                 :            :                           dev_scsi->kernel, sense_key, asc, ascq);
     213                 :            :         } else {
     214         [ #  # ]:          0 :                 if (sb_len < 4)
     215         [ #  # ]:          0 :                         return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
     216                 :            :                                                "%s: sense buffer too small %d bytes, %d bytes too short",
     217                 :            :                                                dev_scsi->kernel, sb_len,
     218                 :            :                                                4 - sb_len);
     219                 :            : 
     220         [ #  # ]:          0 :                 if (sense_buffer[0] < 15)
     221         [ #  # ]:          0 :                         log_debug("%s: old sense key: 0x%x", dev_scsi->kernel, sense_buffer[0] & 0x0f);
     222                 :            :                 else
     223         [ #  # ]:          0 :                         log_debug("%s: sense = %2x %2x",
     224                 :            :                                   dev_scsi->kernel, sense_buffer[0], sense_buffer[2]);
     225         [ #  # ]:          0 :                 log_debug("%s: non-extended sense class %d code 0x%0x",
     226                 :            :                           dev_scsi->kernel, sense_class, code);
     227                 :            : 
     228                 :            :         }
     229                 :            : 
     230                 :          0 :         return -1;
     231                 :            : }
     232                 :            : 
     233                 :          0 : static int scsi_dump(struct scsi_id_device *dev_scsi, struct sg_io_hdr *io) {
     234   [ #  #  #  #  :          0 :         if (!io->status && !io->host_status && !io->msg_status &&
                   #  # ]
     235         [ #  # ]:          0 :             !io->driver_status)
     236                 :            :                 /*
     237                 :            :                  * Impossible, should not be called.
     238                 :            :                  */
     239         [ #  # ]:          0 :                 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
     240                 :            :                                        "%s: called with no error",
     241                 :            :                                        __FUNCTION__);
     242                 :            : 
     243         [ #  # ]:          0 :         log_debug("%s: sg_io failed status 0x%x 0x%x 0x%x 0x%x",
     244                 :            :                   dev_scsi->kernel, io->driver_status, io->host_status, io->msg_status, io->status);
     245         [ #  # ]:          0 :         if (io->status == SCSI_CHECK_CONDITION)
     246                 :          0 :                 return scsi_dump_sense(dev_scsi, io->sbp, io->sb_len_wr);
     247                 :            :         else
     248                 :          0 :                 return -1;
     249                 :            : }
     250                 :            : 
     251                 :          0 : static int scsi_dump_v4(struct scsi_id_device *dev_scsi, struct sg_io_v4 *io) {
     252   [ #  #  #  # ]:          0 :         if (!io->device_status && !io->transport_status &&
     253         [ #  # ]:          0 :             !io->driver_status)
     254                 :            :                 /*
     255                 :            :                  * Impossible, should not be called.
     256                 :            :                  */
     257         [ #  # ]:          0 :                 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
     258                 :            :                                        "%s: called with no error",
     259                 :            :                                        __FUNCTION__);
     260                 :            : 
     261         [ #  # ]:          0 :         log_debug("%s: sg_io failed status 0x%x 0x%x 0x%x",
     262                 :            :                   dev_scsi->kernel, io->driver_status, io->transport_status, io->device_status);
     263         [ #  # ]:          0 :         if (io->device_status == SCSI_CHECK_CONDITION)
     264                 :          0 :                 return scsi_dump_sense(dev_scsi, (unsigned char *)(uintptr_t)io->response,
     265                 :          0 :                                        io->response_len);
     266                 :            :         else
     267                 :          0 :                 return -1;
     268                 :            : }
     269                 :            : 
     270                 :          0 : static int scsi_inquiry(struct scsi_id_device *dev_scsi, int fd,
     271                 :            :                         unsigned char evpd, unsigned char page,
     272                 :            :                         unsigned char *buf, unsigned buflen) {
     273                 :          0 :         unsigned char inq_cmd[INQUIRY_CMDLEN] =
     274                 :            :                 { INQUIRY_CMD, evpd, page, 0, buflen, 0 };
     275                 :            :         unsigned char sense[SENSE_BUFF_LEN];
     276                 :            :         void *io_buf;
     277                 :            :         struct sg_io_v4 io_v4;
     278                 :            :         struct sg_io_hdr io_hdr;
     279                 :          0 :         int retry = 3; /* rather random */
     280                 :            :         int retval;
     281                 :            : 
     282         [ #  # ]:          0 :         if (buflen > SCSI_INQ_BUFF_LEN)
     283         [ #  # ]:          0 :                 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
     284                 :            :                                        "buflen %d too long", buflen);
     285                 :            : 
     286                 :          0 : resend:
     287         [ #  # ]:          0 :         if (dev_scsi->use_sg == 4) {
     288         [ #  # ]:          0 :                 memzero(&io_v4, sizeof(struct sg_io_v4));
     289                 :          0 :                 io_v4.guard = 'Q';
     290                 :          0 :                 io_v4.protocol = BSG_PROTOCOL_SCSI;
     291                 :          0 :                 io_v4.subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD;
     292                 :          0 :                 io_v4.request_len = sizeof(inq_cmd);
     293                 :          0 :                 io_v4.request = (uintptr_t)inq_cmd;
     294                 :          0 :                 io_v4.max_response_len = sizeof(sense);
     295                 :          0 :                 io_v4.response = (uintptr_t)sense;
     296                 :          0 :                 io_v4.din_xfer_len = buflen;
     297                 :          0 :                 io_v4.din_xferp = (uintptr_t)buf;
     298                 :          0 :                 io_buf = (void *)&io_v4;
     299                 :            :         } else {
     300         [ #  # ]:          0 :                 memzero(&io_hdr, sizeof(struct sg_io_hdr));
     301                 :          0 :                 io_hdr.interface_id = 'S';
     302                 :          0 :                 io_hdr.cmd_len = sizeof(inq_cmd);
     303                 :          0 :                 io_hdr.mx_sb_len = sizeof(sense);
     304                 :          0 :                 io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
     305                 :          0 :                 io_hdr.dxfer_len = buflen;
     306                 :          0 :                 io_hdr.dxferp = buf;
     307                 :          0 :                 io_hdr.cmdp = inq_cmd;
     308                 :          0 :                 io_hdr.sbp = sense;
     309                 :          0 :                 io_hdr.timeout = DEF_TIMEOUT;
     310                 :          0 :                 io_buf = (void *)&io_hdr;
     311                 :            :         }
     312                 :            : 
     313                 :          0 :         retval = ioctl(fd, SG_IO, io_buf);
     314         [ #  # ]:          0 :         if (retval < 0) {
     315   [ #  #  #  #  :          0 :                 if (IN_SET(errno, EINVAL, ENOSYS) && dev_scsi->use_sg == 4) {
                   #  # ]
     316                 :          0 :                         dev_scsi->use_sg = 3;
     317                 :          0 :                         goto resend;
     318                 :            :                 }
     319         [ #  # ]:          0 :                 log_debug_errno(errno, "%s: ioctl failed: %m", dev_scsi->kernel);
     320                 :          0 :                 goto error;
     321                 :            :         }
     322                 :            : 
     323         [ #  # ]:          0 :         if (dev_scsi->use_sg == 4)
     324                 :          0 :                 retval = sg_err_category4(io_buf);
     325                 :            :         else
     326                 :          0 :                 retval = sg_err_category3(io_buf);
     327                 :            : 
     328      [ #  #  # ]:          0 :         switch (retval) {
     329                 :          0 :                 case SG_ERR_CAT_NOTSUPPORTED:
     330                 :          0 :                         buf[1] = 0;
     331                 :            :                         _fallthrough_;
     332                 :          0 :                 case SG_ERR_CAT_CLEAN:
     333                 :            :                 case SG_ERR_CAT_RECOVERED:
     334                 :          0 :                         retval = 0;
     335                 :          0 :                         break;
     336                 :            : 
     337                 :          0 :                 default:
     338         [ #  # ]:          0 :                         if (dev_scsi->use_sg == 4)
     339                 :          0 :                                 retval = scsi_dump_v4(dev_scsi, io_buf);
     340                 :            :                         else
     341                 :          0 :                                 retval = scsi_dump(dev_scsi, io_buf);
     342                 :            :         }
     343                 :            : 
     344         [ #  # ]:          0 :         if (!retval) {
     345                 :          0 :                 retval = buflen;
     346         [ #  # ]:          0 :         } else if (retval > 0) {
     347         [ #  # ]:          0 :                 if (--retry > 0)
     348                 :          0 :                         goto resend;
     349                 :          0 :                 retval = -1;
     350                 :            :         }
     351                 :            : 
     352                 :          0 : error:
     353         [ #  # ]:          0 :         if (retval < 0)
     354         [ #  # ]:          0 :                 log_debug("%s: Unable to get INQUIRY vpd %d page 0x%x.",
     355                 :            :                           dev_scsi->kernel, evpd, page);
     356                 :            : 
     357                 :          0 :         return retval;
     358                 :            : }
     359                 :            : 
     360                 :            : /* Get list of supported EVPD pages */
     361                 :          0 : static int do_scsi_page0_inquiry(struct scsi_id_device *dev_scsi, int fd,
     362                 :            :                                  unsigned char *buffer, unsigned len) {
     363                 :            :         int retval;
     364                 :            : 
     365         [ #  # ]:          0 :         memzero(buffer, len);
     366                 :          0 :         retval = scsi_inquiry(dev_scsi, fd, 1, 0x0, buffer, len);
     367         [ #  # ]:          0 :         if (retval < 0)
     368                 :          0 :                 return 1;
     369                 :            : 
     370         [ #  # ]:          0 :         if (buffer[1] != 0) {
     371         [ #  # ]:          0 :                 log_debug("%s: page 0 not available.", dev_scsi->kernel);
     372                 :          0 :                 return 1;
     373                 :            :         }
     374         [ #  # ]:          0 :         if (buffer[3] > len) {
     375         [ #  # ]:          0 :                 log_debug("%s: page 0 buffer too long %d", dev_scsi->kernel, buffer[3]);
     376                 :          0 :                 return 1;
     377                 :            :         }
     378                 :            : 
     379                 :            :         /*
     380                 :            :          * Following check is based on code once included in the 2.5.x
     381                 :            :          * kernel.
     382                 :            :          *
     383                 :            :          * Some ill behaved devices return the standard inquiry here
     384                 :            :          * rather than the evpd data, snoop the data to verify.
     385                 :            :          */
     386         [ #  # ]:          0 :         if (buffer[3] > MODEL_LENGTH) {
     387                 :            :                 /*
     388                 :            :                  * If the vendor id appears in the page assume the page is
     389                 :            :                  * invalid.
     390                 :            :                  */
     391         [ #  # ]:          0 :                 if (strneq((char*) buffer + VENDOR_LENGTH, dev_scsi->vendor, VENDOR_LENGTH)) {
     392         [ #  # ]:          0 :                         log_debug("%s: invalid page0 data", dev_scsi->kernel);
     393                 :          0 :                         return 1;
     394                 :            :                 }
     395                 :            :         }
     396                 :          0 :         return 0;
     397                 :            : }
     398                 :            : 
     399                 :          0 : static int append_vendor_model(
     400                 :            :                 const struct scsi_id_device *dev_scsi,
     401                 :            :                 char buf[static VENDOR_LENGTH + MODEL_LENGTH]) {
     402                 :            : 
     403         [ #  # ]:          0 :         assert(dev_scsi);
     404         [ #  # ]:          0 :         assert(buf);
     405                 :            : 
     406         [ #  # ]:          0 :         if (strnlen(dev_scsi->vendor, VENDOR_LENGTH) != VENDOR_LENGTH)
     407         [ #  # ]:          0 :                 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
     408                 :            :                                        "%s: bad vendor string \"%s\"",
     409                 :            :                                        dev_scsi->kernel, dev_scsi->vendor);
     410         [ #  # ]:          0 :         if (strnlen(dev_scsi->model, MODEL_LENGTH) != MODEL_LENGTH)
     411         [ #  # ]:          0 :                 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
     412                 :            :                                        "%s: bad model string \"%s\"",
     413                 :            :                                        dev_scsi->kernel, dev_scsi->model);
     414                 :          0 :         memcpy(buf, dev_scsi->vendor, VENDOR_LENGTH);
     415                 :          0 :         memcpy(buf + VENDOR_LENGTH, dev_scsi->model, MODEL_LENGTH);
     416                 :          0 :         return VENDOR_LENGTH + MODEL_LENGTH;
     417                 :            : }
     418                 :            : 
     419                 :            : /*
     420                 :            :  * check_fill_0x83_id - check the page 0x83 id, if OK allocate and fill
     421                 :            :  * serial number.
     422                 :            :  */
     423                 :          0 : static int check_fill_0x83_id(struct scsi_id_device *dev_scsi,
     424                 :            :                               unsigned char *page_83,
     425                 :            :                               const struct scsi_id_search_values
     426                 :            :                               *id_search, char *serial, char *serial_short,
     427                 :            :                               int max_len, char *wwn,
     428                 :            :                               char *wwn_vendor_extension, char *tgpt_group) {
     429                 :            :         int i, j, s, len;
     430                 :            : 
     431                 :            :         /*
     432                 :            :          * ASSOCIATION must be with the device (value 0)
     433                 :            :          * or with the target port for SCSI_ID_TGTPORT
     434                 :            :          */
     435         [ #  # ]:          0 :         if ((page_83[1] & 0x30) == 0x10) {
     436         [ #  # ]:          0 :                 if (id_search->id_type != SCSI_ID_TGTGROUP)
     437                 :          0 :                         return 1;
     438         [ #  # ]:          0 :         } else if ((page_83[1] & 0x30) != 0)
     439                 :          0 :                 return 1;
     440                 :            : 
     441         [ #  # ]:          0 :         if ((page_83[1] & 0x0f) != id_search->id_type)
     442                 :          0 :                 return 1;
     443                 :            : 
     444                 :            :         /*
     445                 :            :          * Possibly check NAA sub-type.
     446                 :            :          */
     447         [ #  # ]:          0 :         if ((id_search->naa_type != SCSI_ID_NAA_DONT_CARE) &&
     448         [ #  # ]:          0 :             (id_search->naa_type != (page_83[4] & 0xf0) >> 4))
     449                 :          0 :                 return 1;
     450                 :            : 
     451                 :            :         /*
     452                 :            :          * Check for matching code set - ASCII or BINARY.
     453                 :            :          */
     454         [ #  # ]:          0 :         if ((page_83[0] & 0x0f) != id_search->code_set)
     455                 :          0 :                 return 1;
     456                 :            : 
     457                 :            :         /*
     458                 :            :          * page_83[3]: identifier length
     459                 :            :          */
     460                 :          0 :         len = page_83[3];
     461         [ #  # ]:          0 :         if ((page_83[0] & 0x0f) != SCSI_ID_ASCII)
     462                 :            :                 /*
     463                 :            :                  * If not ASCII, use two bytes for each binary value.
     464                 :            :                  */
     465                 :          0 :                 len *= 2;
     466                 :            : 
     467                 :            :         /*
     468                 :            :          * Add one byte for the NUL termination, and one for the id_type.
     469                 :            :          */
     470                 :          0 :         len += 2;
     471         [ #  # ]:          0 :         if (id_search->id_type == SCSI_ID_VENDOR_SPECIFIC)
     472                 :          0 :                 len += VENDOR_LENGTH + MODEL_LENGTH;
     473                 :            : 
     474         [ #  # ]:          0 :         if (max_len < len) {
     475         [ #  # ]:          0 :                 log_debug("%s: length %d too short - need %d",
     476                 :            :                           dev_scsi->kernel, max_len, len);
     477                 :          0 :                 return 1;
     478                 :            :         }
     479                 :            : 
     480   [ #  #  #  # ]:          0 :         if (id_search->id_type == SCSI_ID_TGTGROUP && tgpt_group != NULL) {
     481                 :            :                 unsigned group;
     482                 :            : 
     483                 :          0 :                 group = ((unsigned)page_83[6] << 8) | page_83[7];
     484                 :          0 :                 sprintf(tgpt_group,"%x", group);
     485                 :          0 :                 return 1;
     486                 :            :         }
     487                 :            : 
     488                 :          0 :         serial[0] = hex_str[id_search->id_type];
     489                 :            : 
     490                 :            :         /*
     491                 :            :          * For SCSI_ID_VENDOR_SPECIFIC prepend the vendor and model before
     492                 :            :          * the id since it is not unique across all vendors and models,
     493                 :            :          * this differs from SCSI_ID_T10_VENDOR, where the vendor is
     494                 :            :          * included in the identifier.
     495                 :            :          */
     496         [ #  # ]:          0 :         if (id_search->id_type == SCSI_ID_VENDOR_SPECIFIC)
     497         [ #  # ]:          0 :                 if (append_vendor_model(dev_scsi, serial + 1) < 0)
     498                 :          0 :                         return 1;
     499                 :            : 
     500                 :          0 :         i = 4; /* offset to the start of the identifier */
     501                 :          0 :         s = j = strlen(serial);
     502         [ #  # ]:          0 :         if ((page_83[0] & 0x0f) == SCSI_ID_ASCII) {
     503                 :            :                 /*
     504                 :            :                  * ASCII descriptor.
     505                 :            :                  */
     506         [ #  # ]:          0 :                 while (i < (4 + page_83[3]))
     507                 :          0 :                         serial[j++] = page_83[i++];
     508                 :            :         } else {
     509                 :            :                 /*
     510                 :            :                  * Binary descriptor, convert to ASCII, using two bytes of
     511                 :            :                  * ASCII for each byte in the page_83.
     512                 :            :                  */
     513         [ #  # ]:          0 :                 while (i < (4 + page_83[3])) {
     514                 :          0 :                         serial[j++] = hex_str[(page_83[i] & 0xf0) >> 4];
     515                 :          0 :                         serial[j++] = hex_str[page_83[i] & 0x0f];
     516                 :          0 :                         i++;
     517                 :            :                 }
     518                 :            :         }
     519                 :            : 
     520                 :          0 :         strcpy(serial_short, serial + s);
     521                 :            : 
     522   [ #  #  #  # ]:          0 :         if (id_search->id_type == SCSI_ID_NAA && wwn != NULL) {
     523                 :          0 :                 strncpy(wwn, serial + s, 16);
     524         [ #  # ]:          0 :                 if (wwn_vendor_extension)
     525                 :          0 :                         strncpy(wwn_vendor_extension, serial + s + 16, 16);
     526                 :            :         }
     527                 :            : 
     528                 :          0 :         return 0;
     529                 :            : }
     530                 :            : 
     531                 :            : /* Extract the raw binary from VPD 0x83 pre-SPC devices */
     532                 :          0 : static int check_fill_0x83_prespc3(struct scsi_id_device *dev_scsi,
     533                 :            :                                    unsigned char *page_83,
     534                 :            :                                    const struct scsi_id_search_values
     535                 :            :                                    *id_search, char *serial, char *serial_short, int max_len) {
     536                 :            :         int i, j;
     537                 :            : 
     538                 :          0 :         serial[0] = hex_str[SCSI_ID_NAA];
     539                 :            :         /* serial has been memset to zero before */
     540                 :          0 :         j = strlen(serial);        /* j = 1; */
     541                 :            : 
     542   [ #  #  #  # ]:          0 :         for (i = 0; (i < page_83[3]) && (j < max_len-3); ++i) {
     543                 :          0 :                 serial[j++] = hex_str[(page_83[4+i] & 0xf0) >> 4];
     544                 :          0 :                 serial[j++] = hex_str[ page_83[4+i] & 0x0f];
     545                 :            :         }
     546                 :          0 :         serial[max_len-1] = 0;
     547                 :          0 :         strncpy(serial_short, serial, max_len-1);
     548                 :          0 :         return 0;
     549                 :            : }
     550                 :            : 
     551                 :            : /* Get device identification VPD page */
     552                 :          0 : static int do_scsi_page83_inquiry(struct scsi_id_device *dev_scsi, int fd,
     553                 :            :                                   char *serial, char *serial_short, int len,
     554                 :            :                                   char *unit_serial_number, char *wwn,
     555                 :            :                                   char *wwn_vendor_extension, char *tgpt_group) {
     556                 :            :         int retval;
     557                 :            :         unsigned id_ind, j;
     558                 :            :         unsigned char page_83[SCSI_INQ_BUFF_LEN];
     559                 :            : 
     560                 :            :         /* also pick up the page 80 serial number */
     561                 :          0 :         do_scsi_page80_inquiry(dev_scsi, fd, NULL, unit_serial_number, MAX_SERIAL_LEN);
     562                 :            : 
     563         [ #  # ]:          0 :         memzero(page_83, SCSI_INQ_BUFF_LEN);
     564                 :          0 :         retval = scsi_inquiry(dev_scsi, fd, 1, PAGE_83, page_83,
     565                 :            :                               SCSI_INQ_BUFF_LEN);
     566         [ #  # ]:          0 :         if (retval < 0)
     567                 :          0 :                 return 1;
     568                 :            : 
     569         [ #  # ]:          0 :         if (page_83[1] != PAGE_83) {
     570         [ #  # ]:          0 :                 log_debug("%s: Invalid page 0x83", dev_scsi->kernel);
     571                 :          0 :                 return 1;
     572                 :            :         }
     573                 :            : 
     574                 :            :         /*
     575                 :            :          * XXX Some devices (IBM 3542) return all spaces for an identifier if
     576                 :            :          * the LUN is not actually configured. This leads to identifiers of
     577                 :            :          * the form: "1            ".
     578                 :            :          */
     579                 :            : 
     580                 :            :         /*
     581                 :            :          * Model 4, 5, and (some) model 6 EMC Symmetrix devices return
     582                 :            :          * a page 83 reply according to SCSI-2 format instead of SPC-2/3.
     583                 :            :          *
     584                 :            :          * The SCSI-2 page 83 format returns an IEEE WWN in binary
     585                 :            :          * encoded hexi-decimal in the 16 bytes following the initial
     586                 :            :          * 4-byte page 83 reply header.
     587                 :            :          *
     588                 :            :          * Both the SPC-2 and SPC-3 formats return an IEEE WWN as part
     589                 :            :          * of an Identification descriptor.  The 3rd byte of the first
     590                 :            :          * Identification descriptor is a reserved (BSZ) byte field.
     591                 :            :          *
     592                 :            :          * Reference the 7th byte of the page 83 reply to determine
     593                 :            :          * whether the reply is compliant with SCSI-2 or SPC-2/3
     594                 :            :          * specifications.  A zero value in the 7th byte indicates
     595                 :            :          * an SPC-2/3 conformant reply, (i.e., the reserved field of the
     596                 :            :          * first Identification descriptor).  This byte will be non-zero
     597                 :            :          * for a SCSI-2 conformant page 83 reply from these EMC
     598                 :            :          * Symmetrix models since the 7th byte of the reply corresponds
     599                 :            :          * to the 4th and 5th nibbles of the 6-byte OUI for EMC, that is,
     600                 :            :          * 0x006048.
     601                 :            :          */
     602                 :            : 
     603         [ #  # ]:          0 :         if (page_83[6] != 0)
     604                 :          0 :                 return check_fill_0x83_prespc3(dev_scsi, page_83, id_search_list,
     605                 :            :                                                serial, serial_short, len);
     606                 :            : 
     607                 :            :         /*
     608                 :            :          * Search for a match in the prioritized id_search_list - since WWN ids
     609                 :            :          * come first we can pick up the WWN in check_fill_0x83_id().
     610                 :            :          */
     611         [ #  # ]:          0 :         for (id_ind = 0;
     612                 :            :              id_ind < sizeof(id_search_list)/sizeof(id_search_list[0]);
     613                 :          0 :              id_ind++) {
     614                 :            :                 /*
     615                 :            :                  * Examine each descriptor returned. There is normally only
     616                 :            :                  * one or a small number of descriptors.
     617                 :            :                  */
     618         [ #  # ]:          0 :                 for (j = 4; j <= ((unsigned)page_83[2] << 8) + (unsigned)page_83[3] + 3; j += page_83[j + 3] + 4) {
     619                 :          0 :                         retval = check_fill_0x83_id(dev_scsi, page_83 + j,
     620                 :          0 :                                                     id_search_list + id_ind,
     621                 :            :                                                     serial, serial_short, len,
     622                 :            :                                                     wwn, wwn_vendor_extension,
     623                 :            :                                                     tgpt_group);
     624         [ #  # ]:          0 :                         if (!retval)
     625                 :          0 :                                 return retval;
     626         [ #  # ]:          0 :                         else if (retval < 0)
     627                 :          0 :                                 return retval;
     628                 :            :                 }
     629                 :            :         }
     630                 :          0 :         return 1;
     631                 :            : }
     632                 :            : 
     633                 :            : /*
     634                 :            :  * Get device identification VPD page for older SCSI-2 device which is not
     635                 :            :  * compliant with either SPC-2 or SPC-3 format.
     636                 :            :  *
     637                 :            :  * Return the hard coded error code value 2 if the page 83 reply is not
     638                 :            :  * conformant to the SCSI-2 format.
     639                 :            :  */
     640                 :          0 : static int do_scsi_page83_prespc3_inquiry(struct scsi_id_device *dev_scsi, int fd,
     641                 :            :                                           char *serial, char *serial_short, int len) {
     642                 :            :         int retval;
     643                 :            :         int i, j;
     644                 :            :         unsigned char page_83[SCSI_INQ_BUFF_LEN];
     645                 :            : 
     646         [ #  # ]:          0 :         memzero(page_83, SCSI_INQ_BUFF_LEN);
     647                 :          0 :         retval = scsi_inquiry(dev_scsi, fd, 1, PAGE_83, page_83, SCSI_INQ_BUFF_LEN);
     648         [ #  # ]:          0 :         if (retval < 0)
     649                 :          0 :                 return 1;
     650                 :            : 
     651         [ #  # ]:          0 :         if (page_83[1] != PAGE_83) {
     652         [ #  # ]:          0 :                 log_debug("%s: Invalid page 0x83", dev_scsi->kernel);
     653                 :          0 :                 return 1;
     654                 :            :         }
     655                 :            :         /*
     656                 :            :          * Model 4, 5, and (some) model 6 EMC Symmetrix devices return
     657                 :            :          * a page 83 reply according to SCSI-2 format instead of SPC-2/3.
     658                 :            :          *
     659                 :            :          * The SCSI-2 page 83 format returns an IEEE WWN in binary
     660                 :            :          * encoded hexi-decimal in the 16 bytes following the initial
     661                 :            :          * 4-byte page 83 reply header.
     662                 :            :          *
     663                 :            :          * Both the SPC-2 and SPC-3 formats return an IEEE WWN as part
     664                 :            :          * of an Identification descriptor.  The 3rd byte of the first
     665                 :            :          * Identification descriptor is a reserved (BSZ) byte field.
     666                 :            :          *
     667                 :            :          * Reference the 7th byte of the page 83 reply to determine
     668                 :            :          * whether the reply is compliant with SCSI-2 or SPC-2/3
     669                 :            :          * specifications.  A zero value in the 7th byte indicates
     670                 :            :          * an SPC-2/3 conformant reply, (i.e., the reserved field of the
     671                 :            :          * first Identification descriptor).  This byte will be non-zero
     672                 :            :          * for a SCSI-2 conformant page 83 reply from these EMC
     673                 :            :          * Symmetrix models since the 7th byte of the reply corresponds
     674                 :            :          * to the 4th and 5th nibbles of the 6-byte OUI for EMC, that is,
     675                 :            :          * 0x006048.
     676                 :            :          */
     677         [ #  # ]:          0 :         if (page_83[6] == 0)
     678                 :          0 :                 return 2;
     679                 :            : 
     680                 :          0 :         serial[0] = hex_str[SCSI_ID_NAA];
     681                 :            :         /*
     682                 :            :          * The first four bytes contain data, not a descriptor.
     683                 :            :          */
     684                 :          0 :         i = 4;
     685                 :          0 :         j = strlen(serial);
     686                 :            :         /*
     687                 :            :          * Binary descriptor, convert to ASCII,
     688                 :            :          * using two bytes of ASCII for each byte
     689                 :            :          * in the page_83.
     690                 :            :          */
     691         [ #  # ]:          0 :         while (i < (page_83[3]+4)) {
     692                 :          0 :                 serial[j++] = hex_str[(page_83[i] & 0xf0) >> 4];
     693                 :          0 :                 serial[j++] = hex_str[page_83[i] & 0x0f];
     694                 :          0 :                 i++;
     695                 :            :         }
     696                 :          0 :         return 0;
     697                 :            : }
     698                 :            : 
     699                 :            : /* Get unit serial number VPD page */
     700                 :          0 : static int do_scsi_page80_inquiry(struct scsi_id_device *dev_scsi, int fd,
     701                 :            :                                   char *serial, char *serial_short, int max_len) {
     702                 :            :         int retval;
     703                 :            :         int ser_ind;
     704                 :            :         int i;
     705                 :            :         int len;
     706                 :            :         unsigned char buf[SCSI_INQ_BUFF_LEN];
     707                 :            : 
     708         [ #  # ]:          0 :         memzero(buf, SCSI_INQ_BUFF_LEN);
     709                 :          0 :         retval = scsi_inquiry(dev_scsi, fd, 1, PAGE_80, buf, SCSI_INQ_BUFF_LEN);
     710         [ #  # ]:          0 :         if (retval < 0)
     711                 :          0 :                 return retval;
     712                 :            : 
     713         [ #  # ]:          0 :         if (buf[1] != PAGE_80) {
     714         [ #  # ]:          0 :                 log_debug("%s: Invalid page 0x80", dev_scsi->kernel);
     715                 :          0 :                 return 1;
     716                 :            :         }
     717                 :            : 
     718                 :          0 :         len = 1 + VENDOR_LENGTH + MODEL_LENGTH + buf[3];
     719         [ #  # ]:          0 :         if (max_len < len) {
     720         [ #  # ]:          0 :                 log_debug("%s: length %d too short - need %d",
     721                 :            :                           dev_scsi->kernel, max_len, len);
     722                 :          0 :                 return 1;
     723                 :            :         }
     724                 :            :         /*
     725                 :            :          * Prepend 'S' to avoid unlikely collision with page 0x83 vendor
     726                 :            :          * specific type where we prepend '0' + vendor + model.
     727                 :            :          */
     728                 :          0 :         len = buf[3];
     729         [ #  # ]:          0 :         if (serial) {
     730                 :          0 :                 serial[0] = 'S';
     731                 :          0 :                 ser_ind = append_vendor_model(dev_scsi, serial + 1);
     732         [ #  # ]:          0 :                 if (ser_ind < 0)
     733                 :          0 :                         return 1;
     734                 :          0 :                 ser_ind++; /* for the leading 'S' */
     735         [ #  # ]:          0 :                 for (i = 4; i < len + 4; i++, ser_ind++)
     736                 :          0 :                         serial[ser_ind] = buf[i];
     737                 :            :         }
     738         [ #  # ]:          0 :         if (serial_short) {
     739                 :          0 :                 memcpy(serial_short, buf + 4, len);
     740                 :          0 :                 serial_short[len] = '\0';
     741                 :            :         }
     742                 :          0 :         return 0;
     743                 :            : }
     744                 :            : 
     745                 :          0 : int scsi_std_inquiry(struct scsi_id_device *dev_scsi, const char *devname) {
     746                 :            :         int fd;
     747                 :            :         unsigned char buf[SCSI_INQ_BUFF_LEN];
     748                 :            :         struct stat statbuf;
     749                 :          0 :         int err = 0;
     750                 :            : 
     751                 :          0 :         fd = open(devname, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
     752         [ #  # ]:          0 :         if (fd < 0) {
     753         [ #  # ]:          0 :                 log_debug_errno(errno, "scsi_id: cannot open %s: %m", devname);
     754                 :          0 :                 return 1;
     755                 :            :         }
     756                 :            : 
     757         [ #  # ]:          0 :         if (fstat(fd, &statbuf) < 0) {
     758         [ #  # ]:          0 :                 log_debug_errno(errno, "scsi_id: cannot stat %s: %m", devname);
     759                 :          0 :                 err = 2;
     760                 :          0 :                 goto out;
     761                 :            :         }
     762                 :          0 :         sprintf(dev_scsi->kernel,"%d:%d", major(statbuf.st_rdev),
     763                 :            :                 minor(statbuf.st_rdev));
     764                 :            : 
     765         [ #  # ]:          0 :         memzero(buf, SCSI_INQ_BUFF_LEN);
     766                 :          0 :         err = scsi_inquiry(dev_scsi, fd, 0, 0, buf, SCSI_INQ_BUFF_LEN);
     767         [ #  # ]:          0 :         if (err < 0)
     768                 :          0 :                 goto out;
     769                 :            : 
     770                 :          0 :         err = 0;
     771                 :          0 :         memcpy(dev_scsi->vendor, buf + 8, 8);
     772                 :          0 :         dev_scsi->vendor[8] = '\0';
     773                 :          0 :         memcpy(dev_scsi->model, buf + 16, 16);
     774                 :          0 :         dev_scsi->model[16] = '\0';
     775                 :          0 :         memcpy(dev_scsi->revision, buf + 32, 4);
     776                 :          0 :         dev_scsi->revision[4] = '\0';
     777                 :          0 :         sprintf(dev_scsi->type,"%x", buf[0] & 0x1f);
     778                 :            : 
     779                 :          0 : out:
     780                 :          0 :         close(fd);
     781                 :          0 :         return err;
     782                 :            : }
     783                 :            : 
     784                 :          0 : int scsi_get_serial(struct scsi_id_device *dev_scsi, const char *devname,
     785                 :            :                     int page_code, int len) {
     786                 :            :         unsigned char page0[SCSI_INQ_BUFF_LEN];
     787                 :          0 :         int fd = -1;
     788                 :            :         int cnt;
     789                 :            :         int ind;
     790                 :            :         int retval;
     791                 :            : 
     792         [ #  # ]:          0 :         memzero(dev_scsi->serial, len);
     793                 :          0 :         initialize_srand();
     794         [ #  # ]:          0 :         for (cnt = 20; cnt > 0; cnt--) {
     795                 :            :                 struct timespec duration;
     796                 :            : 
     797                 :          0 :                 fd = open(devname, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
     798   [ #  #  #  # ]:          0 :                 if (fd >= 0 || errno != EBUSY)
     799                 :            :                         break;
     800                 :          0 :                 duration.tv_sec = 0;
     801                 :          0 :                 duration.tv_nsec = (200 * 1000 * 1000) + (rand() % 100 * 1000 * 1000);
     802                 :          0 :                 nanosleep(&duration, NULL);
     803                 :            :         }
     804         [ #  # ]:          0 :         if (fd < 0)
     805                 :          0 :                 return 1;
     806                 :            : 
     807         [ #  # ]:          0 :         if (page_code == PAGE_80) {
     808         [ #  # ]:          0 :                 if (do_scsi_page80_inquiry(dev_scsi, fd, dev_scsi->serial, dev_scsi->serial_short, len)) {
     809                 :          0 :                         retval = 1;
     810                 :          0 :                         goto completed;
     811                 :            :                 } else  {
     812                 :          0 :                         retval = 0;
     813                 :          0 :                         goto completed;
     814                 :            :                 }
     815         [ #  # ]:          0 :         } else if (page_code == PAGE_83) {
     816         [ #  # ]:          0 :                 if (do_scsi_page83_inquiry(dev_scsi, fd, dev_scsi->serial, dev_scsi->serial_short, len, dev_scsi->unit_serial_number, dev_scsi->wwn, dev_scsi->wwn_vendor_extension, dev_scsi->tgpt_group)) {
     817                 :          0 :                         retval = 1;
     818                 :          0 :                         goto completed;
     819                 :            :                 } else  {
     820                 :          0 :                         retval = 0;
     821                 :          0 :                         goto completed;
     822                 :            :                 }
     823         [ #  # ]:          0 :         } else if (page_code == PAGE_83_PRE_SPC3) {
     824                 :          0 :                 retval = do_scsi_page83_prespc3_inquiry(dev_scsi, fd, dev_scsi->serial, dev_scsi->serial_short, len);
     825         [ #  # ]:          0 :                 if (retval) {
     826                 :            :                         /*
     827                 :            :                          * Fallback to servicing a SPC-2/3 compliant page 83
     828                 :            :                          * inquiry if the page 83 reply format does not
     829                 :            :                          * conform to pre-SPC3 expectations.
     830                 :            :                          */
     831         [ #  # ]:          0 :                         if (retval == 2) {
     832         [ #  # ]:          0 :                                 if (do_scsi_page83_inquiry(dev_scsi, fd, dev_scsi->serial, dev_scsi->serial_short, len, dev_scsi->unit_serial_number, dev_scsi->wwn, dev_scsi->wwn_vendor_extension, dev_scsi->tgpt_group)) {
     833                 :          0 :                                         retval = 1;
     834                 :          0 :                                         goto completed;
     835                 :            :                                 } else  {
     836                 :          0 :                                         retval = 0;
     837                 :          0 :                                         goto completed;
     838                 :            :                                 }
     839                 :            :                         }
     840                 :            :                         else {
     841                 :          0 :                                 retval = 1;
     842                 :          0 :                                 goto completed;
     843                 :            :                         }
     844                 :            :                 } else  {
     845                 :          0 :                         retval = 0;
     846                 :          0 :                         goto completed;
     847                 :            :                 }
     848         [ #  # ]:          0 :         } else if (page_code != 0x00) {
     849         [ #  # ]:          0 :                 log_debug("%s: unsupported page code 0x%d", dev_scsi->kernel, page_code);
     850                 :          0 :                 retval = 1;
     851                 :          0 :                 goto completed;
     852                 :            :         }
     853                 :            : 
     854                 :            :         /*
     855                 :            :          * Get page 0, the page of the pages. By default, try from best to
     856                 :            :          * worst of supported pages: 0x83 then 0x80.
     857                 :            :          */
     858         [ #  # ]:          0 :         if (do_scsi_page0_inquiry(dev_scsi, fd, page0, SCSI_INQ_BUFF_LEN)) {
     859                 :            :                 /*
     860                 :            :                  * Don't try anything else. Black list if a specific page
     861                 :            :                  * should be used for this vendor+model, or maybe have an
     862                 :            :                  * optional fall-back to page 0x80 or page 0x83.
     863                 :            :                  */
     864                 :          0 :                 retval = 1;
     865                 :          0 :                 goto completed;
     866                 :            :         }
     867                 :            : 
     868         [ #  # ]:          0 :         for (ind = 4; ind <= page0[3] + 3; ind++)
     869         [ #  # ]:          0 :                 if (page0[ind] == PAGE_83)
     870         [ #  # ]:          0 :                         if (!do_scsi_page83_inquiry(dev_scsi, fd,
     871                 :          0 :                                                     dev_scsi->serial, dev_scsi->serial_short, len, dev_scsi->unit_serial_number, dev_scsi->wwn, dev_scsi->wwn_vendor_extension, dev_scsi->tgpt_group)) {
     872                 :            :                                 /*
     873                 :            :                                  * Success
     874                 :            :                                  */
     875                 :          0 :                                 retval = 0;
     876                 :          0 :                                 goto completed;
     877                 :            :                         }
     878                 :            : 
     879         [ #  # ]:          0 :         for (ind = 4; ind <= page0[3] + 3; ind++)
     880         [ #  # ]:          0 :                 if (page0[ind] == PAGE_80)
     881         [ #  # ]:          0 :                         if (!do_scsi_page80_inquiry(dev_scsi, fd,
     882                 :          0 :                                                     dev_scsi->serial, dev_scsi->serial_short, len)) {
     883                 :            :                                 /*
     884                 :            :                                  * Success
     885                 :            :                                  */
     886                 :          0 :                                 retval = 0;
     887                 :          0 :                                 goto completed;
     888                 :            :                         }
     889                 :          0 :         retval = 1;
     890                 :            : 
     891                 :          0 : completed:
     892                 :          0 :         close(fd);
     893                 :          0 :         return retval;
     894                 :            : }

Generated by: LCOV version 1.14