LCOV - code coverage report
Current view: top level - lib/scsi - task.c (source / functions) Hit Total Coverage
Test: ut_cov_unit.info Lines: 112 128 87.5 %
Date: 2024-12-14 00:46:58 Functions: 10 12 83.3 %

          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           2 : scsi_task_free_data(struct spdk_scsi_task *task)
      14             : {
      15           2 :         if (task->alloc_len != 0) {
      16           1 :                 spdk_dma_free(task->iov.iov_base);
      17           1 :                 task->alloc_len = 0;
      18             :         }
      19             : 
      20           2 :         task->iov.iov_base = NULL;
      21           2 :         task->iov.iov_len = 0;
      22           2 : }
      23             : 
      24             : void
      25           2 : spdk_scsi_task_put(struct spdk_scsi_task *task)
      26             : {
      27           2 :         if (!task) {
      28           0 :                 return;
      29             :         }
      30             : 
      31           2 :         assert(task->ref > 0);
      32           2 :         task->ref--;
      33             : 
      34           2 :         if (task->ref == 0) {
      35           2 :                 struct spdk_bdev_io *bdev_io = task->bdev_io;
      36             : 
      37           2 :                 if (bdev_io) {
      38           0 :                         spdk_bdev_free_io(bdev_io);
      39             :                 }
      40             : 
      41           2 :                 scsi_task_free_data(task);
      42             : 
      43           2 :                 task->free_fn(task);
      44             :         }
      45             : }
      46             : 
      47             : void
      48          23 : 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          23 :         assert(task != NULL);
      53          23 :         assert(cpl_fn != NULL);
      54          23 :         assert(free_fn != NULL);
      55             : 
      56          23 :         task->cpl_fn = cpl_fn;
      57          23 :         task->free_fn = free_fn;
      58             : 
      59          23 :         task->ref++;
      60             : 
      61             :         /*
      62             :          * Pre-fill the iov_buffers to point to the embedded iov
      63             :          */
      64          23 :         assert(task->iov.iov_base == NULL);
      65          23 :         task->iovs = &task->iov;
      66          23 :         task->iovcnt = 1;
      67          23 : }
      68             : 
      69             : static void *
      70           4 : scsi_task_alloc_data(struct spdk_scsi_task *task, uint32_t alloc_len)
      71             : {
      72             :         uint32_t zmalloc_len;
      73             : 
      74           4 :         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           4 :         zmalloc_len = 4 * spdk_divide_round_up(alloc_len, 4);
      82           4 :         task->iov.iov_base = spdk_dma_zmalloc(zmalloc_len, 0, NULL);
      83           4 :         task->iov.iov_len = alloc_len;
      84           4 :         task->alloc_len = alloc_len;
      85             : 
      86           4 :         return task->iov.iov_base;
      87             : }
      88             : 
      89             : int
      90         261 : spdk_scsi_task_scatter_data(struct spdk_scsi_task *task, const void *src, size_t buf_len)
      91             : {
      92         261 :         size_t len = 0;
      93         261 :         size_t buf_left = buf_len;
      94             :         int i;
      95         261 :         struct iovec *iovs = task->iovs;
      96             :         const uint8_t *pos;
      97             : 
      98         261 :         if (buf_len == 0) {
      99           2 :                 return 0;
     100             :         }
     101             : 
     102         259 :         if (task->iovcnt == 1 && iovs[0].iov_base == NULL) {
     103           4 :                 scsi_task_alloc_data(task, buf_len);
     104           4 :                 iovs[0] = task->iov;
     105             :         }
     106             : 
     107         518 :         for (i = 0; i < task->iovcnt; i++) {
     108         259 :                 assert(iovs[i].iov_base != NULL);
     109         259 :                 len += iovs[i].iov_len;
     110             :         }
     111             : 
     112         259 :         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         259 :         pos = src;
     121             : 
     122         518 :         for (i = 0; i < task->iovcnt; i++) {
     123         259 :                 len = spdk_min(iovs[i].iov_len, buf_left);
     124         259 :                 buf_left -= len;
     125         259 :                 memcpy(iovs[i].iov_base, pos, len);
     126         259 :                 pos += len;
     127             :         }
     128             : 
     129         259 :         return buf_len;
     130             : }
     131             : 
     132             : void *
     133           1 : spdk_scsi_task_gather_data(struct spdk_scsi_task *task, int *len)
     134             : {
     135             :         int i;
     136           1 :         struct iovec *iovs = task->iovs;
     137           1 :         size_t buf_len = 0;
     138             :         uint8_t *buf, *pos;
     139             : 
     140           2 :         for (i = 0; i < task->iovcnt; i++) {
     141             :                 /* It is OK for iov_base to be NULL if iov_len is 0. */
     142           1 :                 assert(iovs[i].iov_base != NULL || iovs[i].iov_len == 0);
     143           1 :                 buf_len += iovs[i].iov_len;
     144             :         }
     145             : 
     146           1 :         if (buf_len == 0) {
     147           0 :                 *len = 0;
     148           0 :                 return NULL;
     149             :         }
     150             : 
     151           1 :         buf = calloc(1, buf_len);
     152           1 :         if (buf == NULL) {
     153           0 :                 *len = -1;
     154           0 :                 return NULL;
     155             :         }
     156             : 
     157           1 :         pos = buf;
     158           2 :         for (i = 0; i < task->iovcnt; i++) {
     159           1 :                 memcpy(pos, iovs[i].iov_base, iovs[i].iov_len);
     160           1 :                 pos += iovs[i].iov_len;
     161             :         }
     162             : 
     163           1 :         *len = buf_len;
     164           1 :         return buf;
     165             : }
     166             : 
     167             : void
     168         260 : spdk_scsi_task_set_data(struct spdk_scsi_task *task, void *data, uint32_t len)
     169             : {
     170         260 :         assert(task->iovcnt == 1);
     171         260 :         assert(task->alloc_len == 0);
     172             : 
     173         260 :         task->iovs[0].iov_base = data;
     174         260 :         task->iovs[0].iov_len = len;
     175         260 : }
     176             : 
     177             : void
     178           9 : 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           9 :         resp_code = 0x70; /* Current + Fixed format */
     184             : 
     185             :         /* Sense Data */
     186           9 :         cp = task->sense_data;
     187             : 
     188             :         /* VALID(7) RESPONSE CODE(6-0) */
     189           9 :         cp[0] = 0x80 | resp_code;
     190             :         /* Obsolete */
     191           9 :         cp[1] = 0;
     192             :         /* FILEMARK(7) EOM(6) ILI(5) SENSE KEY(3-0) */
     193           9 :         cp[2] = sk & 0xf;
     194             :         /* INFORMATION */
     195           9 :         memset(&cp[3], 0, 4);
     196             : 
     197             :         /* ADDITIONAL SENSE LENGTH */
     198           9 :         cp[7] = 10;
     199             : 
     200             :         /* COMMAND-SPECIFIC INFORMATION */
     201           9 :         memset(&cp[8], 0, 4);
     202             :         /* ADDITIONAL SENSE CODE */
     203           9 :         cp[12] = asc;
     204             :         /* ADDITIONAL SENSE CODE QUALIFIER */
     205           9 :         cp[13] = ascq;
     206             :         /* FIELD REPLACEABLE UNIT CODE */
     207           9 :         cp[14] = 0;
     208             : 
     209             :         /* SKSV(7) SENSE KEY SPECIFIC(6-0,7-0,7-0) */
     210           9 :         cp[15] = 0;
     211           9 :         cp[16] = 0;
     212           9 :         cp[17] = 0;
     213             : 
     214             :         /* SenseLength */
     215           9 :         task->sense_data_len = 18;
     216           9 : }
     217             : 
     218             : void
     219          20 : spdk_scsi_task_set_status(struct spdk_scsi_task *task, int sc, int sk,
     220             :                           int asc, int ascq)
     221             : {
     222          20 :         if (sc == SPDK_SCSI_STATUS_CHECK_CONDITION) {
     223           9 :                 spdk_scsi_task_build_sense_data(task, sk, asc, ascq);
     224             :         }
     225          20 :         task->status = sc;
     226          20 : }
     227             : 
     228             : void
     229           0 : spdk_scsi_task_copy_status(struct spdk_scsi_task *dst,
     230             :                            struct spdk_scsi_task *src)
     231             : {
     232           0 :         memcpy(dst->sense_data, src->sense_data, src->sense_data_len);
     233           0 :         dst->sense_data_len = src->sense_data_len;
     234           0 :         dst->status = src->status;
     235           0 : }
     236             : 
     237             : void
     238           3 : spdk_scsi_task_process_null_lun(struct spdk_scsi_task *task)
     239             : {
     240           3 :         uint8_t buffer[36];
     241             :         uint32_t allocation_len;
     242             :         uint32_t data_len;
     243             : 
     244           3 :         task->length = task->transfer_len;
     245           3 :         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           2 :                 data_len = sizeof(buffer);
     252             : 
     253           2 :                 memset(buffer, 0, data_len);
     254             :                 /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
     255           2 :                 buffer[0] = 0x03 << 5 | 0x1f;
     256             :                 /* ADDITIONAL LENGTH */
     257           2 :                 buffer[4] = data_len - 5;
     258             : 
     259           2 :                 allocation_len = from_be16(&task->cdb[3]);
     260           2 :                 if (spdk_scsi_task_scatter_data(task, buffer, spdk_min(allocation_len, data_len)) >= 0) {
     261           2 :                         task->data_transferred = data_len;
     262           2 :                         task->status = SPDK_SCSI_STATUS_GOOD;
     263             :                 }
     264             :         } else {
     265             :                 /* LOGICAL UNIT NOT SUPPORTED */
     266           1 :                 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           1 :                 task->data_transferred = 0;
     271             :         }
     272           3 : }
     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.15