LCOV - code coverage report
Current view: top level - spdk/lib/scsi - task.c (source / functions) Hit Total Coverage
Test: Combined Lines: 118 142 83.1 %
Date: 2024-11-19 03:27:24 Functions: 11 12 91.7 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 47 474 9.9 %

           Branch data     Line data    Source code
       1                 :            : /*   SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  *   Copyright (C) 2008-2012 Daisuke Aoyama <aoyama@peach.ne.jp>.
       3                 :            :  *   Copyright (C) 2016 Intel Corporation.
       4                 :            :  *   All rights reserved.
       5                 :            :  */
       6                 :            : 
       7                 :            : #include "scsi_internal.h"
       8                 :            : #include "spdk/endian.h"
       9                 :            : #include "spdk/env.h"
      10                 :            : #include "spdk/util.h"
      11                 :            : 
      12                 :            : static void
      13                 :   30777080 : scsi_task_free_data(struct spdk_scsi_task *task)
      14                 :            : {
      15   [ +  +  #  #  :   30777080 :         if (task->alloc_len != 0) {
                   #  # ]
      16   [ #  #  #  #  :      20435 :                 spdk_dma_free(task->iov.iov_base);
                   #  # ]
      17   [ #  #  #  # ]:      20435 :                 task->alloc_len = 0;
      18                 :          0 :         }
      19                 :            : 
      20   [ #  #  #  #  :   30777080 :         task->iov.iov_base = NULL;
                   #  # ]
      21   [ #  #  #  #  :   30777080 :         task->iov.iov_len = 0;
                   #  # ]
      22                 :   30777080 : }
      23                 :            : 
      24                 :            : void
      25                 :   56211420 : spdk_scsi_task_put(struct spdk_scsi_task *task)
      26                 :            : {
      27         [ -  + ]:   56211420 :         if (!task) {
      28                 :          0 :                 return;
      29                 :            :         }
      30                 :            : 
      31   [ -  +  #  #  :   56211420 :         assert(task->ref > 0);
             #  #  #  # ]
      32         [ #  # ]:   56211420 :         task->ref--;
      33                 :            : 
      34   [ +  +  #  #  :   56211420 :         if (task->ref == 0) {
                   #  # ]
      35   [ #  #  #  # ]:   30777080 :                 struct spdk_bdev_io *bdev_io = task->bdev_io;
      36                 :            : 
      37         [ +  + ]:   30777080 :                 if (bdev_io) {
      38                 :   15664416 :                         spdk_bdev_free_io(bdev_io);
      39                 :          0 :                 }
      40                 :            : 
      41                 :   30777080 :                 scsi_task_free_data(task);
      42                 :            : 
      43   [ #  #  #  #  :   30777080 :                 task->free_fn(task);
             #  #  #  # ]
      44                 :          0 :         }
      45                 :          0 : }
      46                 :            : 
      47                 :            : void
      48                 :   30777731 : spdk_scsi_task_construct(struct spdk_scsi_task *task,
      49                 :            :                          spdk_scsi_task_cpl cpl_fn,
      50                 :            :                          spdk_scsi_task_free free_fn)
      51                 :            : {
      52   [ -  +  #  # ]:   30777731 :         assert(task != NULL);
      53   [ -  +  #  # ]:   30777731 :         assert(cpl_fn != NULL);
      54   [ -  +  #  # ]:   30777731 :         assert(free_fn != NULL);
      55                 :            : 
      56   [ #  #  #  # ]:   30777731 :         task->cpl_fn = cpl_fn;
      57   [ #  #  #  # ]:   30777731 :         task->free_fn = free_fn;
      58                 :            : 
      59         [ #  # ]:   30777731 :         task->ref++;
      60                 :            : 
      61                 :            :         /*
      62                 :            :          * Pre-fill the iov_buffers to point to the embedded iov
      63                 :            :          */
      64   [ -  +  #  #  :   30777731 :         assert(task->iov.iov_base == NULL);
          #  #  #  #  #  
                      # ]
      65   [ #  #  #  #  :   30777731 :         task->iovs = &task->iov;
                   #  # ]
      66   [ #  #  #  # ]:   30777731 :         task->iovcnt = 1;
      67                 :   30777731 : }
      68                 :            : 
      69                 :            : static void *
      70                 :      20444 : scsi_task_alloc_data(struct spdk_scsi_task *task, uint32_t alloc_len)
      71                 :            : {
      72                 :            :         uint32_t zmalloc_len;
      73                 :            : 
      74   [ -  +  #  #  :      20444 :         assert(task->alloc_len == 0);
             #  #  #  # ]
      75                 :            : 
      76                 :            :         /* Some ULPs (such as iSCSI) need to round len up to nearest
      77                 :            :          * 4 bytes. We can help those ULPs by allocating memory here
      78                 :            :          * up to next 4 byte boundary, so they don't have to worry
      79                 :            :          * about handling out-of-bounds errors.
      80                 :            :          */
      81                 :      20444 :         zmalloc_len = 4 * spdk_divide_round_up(alloc_len, 4);
      82   [ #  #  #  #  :      20444 :         task->iov.iov_base = spdk_dma_zmalloc(zmalloc_len, 0, NULL);
                   #  # ]
      83   [ #  #  #  #  :      20444 :         task->iov.iov_len = alloc_len;
                   #  # ]
      84   [ #  #  #  # ]:      20444 :         task->alloc_len = alloc_len;
      85                 :            : 
      86   [ #  #  #  #  :      20444 :         return task->iov.iov_base;
                   #  # ]
      87                 :            : }
      88                 :            : 
      89                 :            : int
      90                 :      23199 : spdk_scsi_task_scatter_data(struct spdk_scsi_task *task, const void *src, size_t buf_len)
      91                 :            : {
      92                 :      23199 :         size_t len = 0;
      93                 :      23199 :         size_t buf_left = buf_len;
      94                 :            :         int i;
      95   [ #  #  #  # ]:      23199 :         struct iovec *iovs = task->iovs;
      96                 :            :         const uint8_t *pos;
      97                 :            : 
      98         [ +  + ]:      23199 :         if (buf_len == 0) {
      99                 :          8 :                 return 0;
     100                 :            :         }
     101                 :            : 
     102   [ +  -  +  +  :      23191 :         if (task->iovcnt == 1 && iovs[0].iov_base == NULL) {
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     103                 :      20444 :                 scsi_task_alloc_data(task, buf_len);
     104   [ #  #  #  # ]:      20444 :                 iovs[0] = task->iov;
     105                 :          0 :         }
     106                 :            : 
     107   [ +  +  #  #  :      46382 :         for (i = 0; i < task->iovcnt; i++) {
             #  #  #  # ]
     108   [ -  +  #  #  :      23191 :                 assert(iovs[i].iov_base != NULL);
          #  #  #  #  #  
                      # ]
     109   [ #  #  #  #  :      23191 :                 len += iovs[i].iov_len;
                   #  # ]
     110                 :          0 :         }
     111                 :            : 
     112         [ -  + ]:      23191 :         if (len < buf_len) {
     113                 :          0 :                 spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
     114                 :            :                                           SPDK_SCSI_SENSE_ILLEGAL_REQUEST,
     115                 :            :                                           SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB,
     116                 :            :                                           SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
     117                 :          0 :                 return -1;
     118                 :            :         }
     119                 :            : 
     120                 :      23191 :         pos = src;
     121                 :            : 
     122   [ +  +  #  #  :      46382 :         for (i = 0; i < task->iovcnt; i++) {
             #  #  #  # ]
     123   [ #  #  #  #  :      23191 :                 len = spdk_min(iovs[i].iov_len, buf_left);
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     124                 :      23191 :                 buf_left -= len;
     125   [ -  +  -  +  :      23191 :                 memcpy(iovs[i].iov_base, pos, len);
          #  #  #  #  #  
                      # ]
     126         [ #  # ]:      23191 :                 pos += len;
     127                 :          0 :         }
     128                 :            : 
     129                 :      23191 :         return buf_len;
     130                 :          0 : }
     131                 :            : 
     132                 :            : void *
     133                 :          3 : spdk_scsi_task_gather_data(struct spdk_scsi_task *task, int *len)
     134                 :            : {
     135                 :            :         int i;
     136   [ #  #  #  # ]:          3 :         struct iovec *iovs = task->iovs;
     137                 :          3 :         size_t buf_len = 0;
     138                 :            :         uint8_t *buf, *pos;
     139                 :            : 
     140   [ +  +  #  #  :          6 :         for (i = 0; i < task->iovcnt; i++) {
             #  #  #  # ]
     141                 :            :                 /* It is OK for iov_base to be NULL if iov_len is 0. */
     142   [ -  +  -  -  :          3 :                 assert(iovs[i].iov_base != NULL || iovs[i].iov_len == 0);
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
     143   [ #  #  #  #  :          3 :                 buf_len += iovs[i].iov_len;
                   #  # ]
     144                 :          0 :         }
     145                 :            : 
     146         [ -  + ]:          3 :         if (buf_len == 0) {
     147         [ #  # ]:          0 :                 *len = 0;
     148                 :          0 :                 return NULL;
     149                 :            :         }
     150                 :            : 
     151                 :          3 :         buf = calloc(1, buf_len);
     152         [ -  + ]:          3 :         if (buf == NULL) {
     153         [ #  # ]:          0 :                 *len = -1;
     154                 :          0 :                 return NULL;
     155                 :            :         }
     156                 :            : 
     157                 :          3 :         pos = buf;
     158   [ +  +  #  #  :          6 :         for (i = 0; i < task->iovcnt; i++) {
             #  #  #  # ]
     159   [ -  +  -  +  :          3 :                 memcpy(pos, iovs[i].iov_base, iovs[i].iov_len);
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     160   [ #  #  #  #  :          3 :                 pos += iovs[i].iov_len;
             #  #  #  # ]
     161                 :          0 :         }
     162                 :            : 
     163         [ #  # ]:          3 :         *len = buf_len;
     164                 :          3 :         return buf;
     165                 :          0 : }
     166                 :            : 
     167                 :            : void
     168                 :   22734552 : spdk_scsi_task_set_data(struct spdk_scsi_task *task, void *data, uint32_t len)
     169                 :            : {
     170   [ -  +  #  #  :   22734552 :         assert(task->iovcnt == 1);
             #  #  #  # ]
     171   [ -  +  #  #  :   22734552 :         assert(task->alloc_len == 0);
             #  #  #  # ]
     172                 :            : 
     173   [ #  #  #  #  :   22734552 :         task->iovs[0].iov_base = data;
          #  #  #  #  #  
                      # ]
     174   [ #  #  #  #  :   22734552 :         task->iovs[0].iov_len = len;
          #  #  #  #  #  
                      # ]
     175                 :   22734552 : }
     176                 :            : 
     177                 :            : void
     178                 :      70728 : spdk_scsi_task_build_sense_data(struct spdk_scsi_task *task, int sk, int asc, int ascq)
     179                 :            : {
     180                 :            :         uint8_t *cp;
     181                 :            :         int resp_code;
     182                 :            : 
     183                 :      70728 :         resp_code = 0x70; /* Current + Fixed format */
     184                 :            : 
     185                 :            :         /* Sense Data */
     186         [ #  # ]:      70728 :         cp = task->sense_data;
     187                 :            : 
     188                 :            :         /* VALID(7) RESPONSE CODE(6-0) */
     189   [ #  #  #  # ]:      70728 :         cp[0] = 0x80 | resp_code;
     190                 :            :         /* Obsolete */
     191   [ #  #  #  # ]:      70728 :         cp[1] = 0;
     192                 :            :         /* FILEMARK(7) EOM(6) ILI(5) SENSE KEY(3-0) */
     193   [ #  #  #  # ]:      70728 :         cp[2] = sk & 0xf;
     194                 :            :         /* INFORMATION */
     195   [ -  +  #  # ]:      70728 :         memset(&cp[3], 0, 4);
     196                 :            : 
     197                 :            :         /* ADDITIONAL SENSE LENGTH */
     198   [ #  #  #  # ]:      70728 :         cp[7] = 10;
     199                 :            : 
     200                 :            :         /* COMMAND-SPECIFIC INFORMATION */
     201   [ -  +  #  # ]:      70728 :         memset(&cp[8], 0, 4);
     202                 :            :         /* ADDITIONAL SENSE CODE */
     203   [ #  #  #  # ]:      70728 :         cp[12] = asc;
     204                 :            :         /* ADDITIONAL SENSE CODE QUALIFIER */
     205   [ #  #  #  # ]:      70728 :         cp[13] = ascq;
     206                 :            :         /* FIELD REPLACEABLE UNIT CODE */
     207   [ #  #  #  # ]:      70728 :         cp[14] = 0;
     208                 :            : 
     209                 :            :         /* SKSV(7) SENSE KEY SPECIFIC(6-0,7-0,7-0) */
     210   [ #  #  #  # ]:      70728 :         cp[15] = 0;
     211   [ #  #  #  # ]:      70728 :         cp[16] = 0;
     212   [ #  #  #  # ]:      70728 :         cp[17] = 0;
     213                 :            : 
     214                 :            :         /* SenseLength */
     215   [ #  #  #  # ]:      70728 :         task->sense_data_len = 18;
     216                 :      70728 : }
     217                 :            : 
     218                 :            : void
     219                 :   29282895 : spdk_scsi_task_set_status(struct spdk_scsi_task *task, int sc, int sk,
     220                 :            :                           int asc, int ascq)
     221                 :            : {
     222         [ +  + ]:   29282895 :         if (sc == SPDK_SCSI_STATUS_CHECK_CONDITION) {
     223                 :      70728 :                 spdk_scsi_task_build_sense_data(task, sk, asc, ascq);
     224                 :          0 :         }
     225   [ #  #  #  # ]:   29282895 :         task->status = sc;
     226                 :   29282895 : }
     227                 :            : 
     228                 :            : void
     229                 :          2 : spdk_scsi_task_copy_status(struct spdk_scsi_task *dst,
     230                 :            :                            struct spdk_scsi_task *src)
     231                 :            : {
     232   [ -  +  -  +  :          2 :         memcpy(dst->sense_data, src->sense_data, src->sense_data_len);
          #  #  #  #  #  
                #  #  # ]
     233   [ #  #  #  #  :          2 :         dst->sense_data_len = src->sense_data_len;
             #  #  #  # ]
     234   [ #  #  #  #  :          2 :         dst->status = src->status;
             #  #  #  # ]
     235                 :          2 : }
     236                 :            : 
     237                 :            : void
     238                 :      63987 : spdk_scsi_task_process_null_lun(struct spdk_scsi_task *task)
     239                 :            : {
     240                 :          9 :         uint8_t buffer[36];
     241                 :            :         uint32_t allocation_len;
     242                 :            :         uint32_t data_len;
     243                 :            : 
     244   [ #  #  #  #  :      63987 :         task->length = task->transfer_len;
             #  #  #  # ]
     245   [ +  +  #  #  :      63987 :         if (task->cdb[0] == SPDK_SPC_INQUIRY) {
          #  #  #  #  #  
                      # ]
     246                 :            :                 /*
     247                 :            :                  * SPC-4 states that INQUIRY commands to an unsupported LUN
     248                 :            :                  *  must be served with PERIPHERAL QUALIFIER = 0x3 and
     249                 :            :                  *  PERIPHERAL DEVICE TYPE = 0x1F.
     250                 :            :                  */
     251                 :        250 :                 data_len = sizeof(buffer);
     252                 :            : 
     253         [ -  + ]:        250 :                 memset(buffer, 0, data_len);
     254                 :            :                 /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
     255   [ #  #  #  #  :        250 :                 buffer[0] = 0x03 << 5 | 0x1f;
             #  #  #  # ]
     256                 :            :                 /* ADDITIONAL LENGTH */
     257   [ #  #  #  #  :        250 :                 buffer[4] = data_len - 5;
                   #  # ]
     258                 :            : 
     259   [ #  #  #  #  :        250 :                 allocation_len = from_be16(&task->cdb[3]);
                   #  # ]
     260   [ +  -  #  # ]:        250 :                 if (spdk_scsi_task_scatter_data(task, buffer, spdk_min(allocation_len, data_len)) >= 0) {
     261   [ #  #  #  # ]:        250 :                         task->data_transferred = data_len;
     262   [ #  #  #  # ]:        250 :                         task->status = SPDK_SCSI_STATUS_GOOD;
     263                 :          0 :                 }
     264                 :          0 :         } else {
     265                 :            :                 /* LOGICAL UNIT NOT SUPPORTED */
     266                 :      63737 :                 spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
     267                 :            :                                           SPDK_SCSI_SENSE_ILLEGAL_REQUEST,
     268                 :            :                                           SPDK_SCSI_ASC_LOGICAL_UNIT_NOT_SUPPORTED,
     269                 :            :                                           SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
     270   [ #  #  #  # ]:      63737 :                 task->data_transferred = 0;
     271                 :            :         }
     272                 :      63987 : }
     273                 :            : 
     274                 :            : void
     275                 :          0 : spdk_scsi_task_process_abort(struct spdk_scsi_task *task)
     276                 :            : {
     277                 :          0 :         spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
     278                 :            :                                   SPDK_SCSI_SENSE_ABORTED_COMMAND,
     279                 :            :                                   SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE,
     280                 :            :                                   SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
     281                 :          0 : }

Generated by: LCOV version 1.14