diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:45:59 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:45:59 +0000 |
commit | 19fcec84d8d7d21e796c7624e521b60d28ee21ed (patch) | |
tree | 42d26aa27d1e3f7c0b8bd3fd14e7d7082f5008dc /src/spdk/lib/scsi/task.c | |
parent | Initial commit. (diff) | |
download | ceph-6d07fdb6bb33b1af39833b850bb6cf8af79fe293.tar.xz ceph-6d07fdb6bb33b1af39833b850bb6cf8af79fe293.zip |
Adding upstream version 16.2.11+ds.upstream/16.2.11+dsupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/spdk/lib/scsi/task.c')
-rw-r--r-- | src/spdk/lib/scsi/task.c | 300 |
1 files changed, 300 insertions, 0 deletions
diff --git a/src/spdk/lib/scsi/task.c b/src/spdk/lib/scsi/task.c new file mode 100644 index 000000000..7fd8305ec --- /dev/null +++ b/src/spdk/lib/scsi/task.c @@ -0,0 +1,300 @@ +/*- + * BSD LICENSE + * + * Copyright (C) 2008-2012 Daisuke Aoyama <aoyama@peach.ne.jp>. + * Copyright (c) Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "scsi_internal.h" +#include "spdk/endian.h" +#include "spdk/env.h" +#include "spdk/util.h" + +static void +scsi_task_free_data(struct spdk_scsi_task *task) +{ + if (task->alloc_len != 0) { + spdk_dma_free(task->iov.iov_base); + task->alloc_len = 0; + } + + task->iov.iov_base = NULL; + task->iov.iov_len = 0; +} + +void +spdk_scsi_task_put(struct spdk_scsi_task *task) +{ + if (!task) { + return; + } + + assert(task->ref > 0); + task->ref--; + + if (task->ref == 0) { + struct spdk_bdev_io *bdev_io = task->bdev_io; + + if (bdev_io) { + spdk_bdev_free_io(bdev_io); + } + + scsi_task_free_data(task); + + task->free_fn(task); + } +} + +void +spdk_scsi_task_construct(struct spdk_scsi_task *task, + spdk_scsi_task_cpl cpl_fn, + spdk_scsi_task_free free_fn) +{ + assert(task != NULL); + assert(cpl_fn != NULL); + assert(free_fn != NULL); + + task->cpl_fn = cpl_fn; + task->free_fn = free_fn; + + task->ref++; + + /* + * Pre-fill the iov_buffers to point to the embedded iov + */ + assert(task->iov.iov_base == NULL); + task->iovs = &task->iov; + task->iovcnt = 1; +} + +static void * +scsi_task_alloc_data(struct spdk_scsi_task *task, uint32_t alloc_len) +{ + assert(task->alloc_len == 0); + + task->iov.iov_base = spdk_dma_zmalloc(alloc_len, 0, NULL); + task->iov.iov_len = alloc_len; + task->alloc_len = alloc_len; + + return task->iov.iov_base; +} + +int +spdk_scsi_task_scatter_data(struct spdk_scsi_task *task, const void *src, size_t buf_len) +{ + size_t len = 0; + size_t buf_left = buf_len; + int i; + struct iovec *iovs = task->iovs; + const uint8_t *pos; + + if (buf_len == 0) { + return 0; + } + + if (task->iovcnt == 1 && iovs[0].iov_base == NULL) { + scsi_task_alloc_data(task, buf_len); + iovs[0] = task->iov; + } + + for (i = 0; i < task->iovcnt; i++) { + assert(iovs[i].iov_base != NULL); + len += iovs[i].iov_len; + } + + if (len < buf_len) { + spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION, + SPDK_SCSI_SENSE_ILLEGAL_REQUEST, + SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB, + SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE); + return -1; + } + + pos = src; + + for (i = 0; i < task->iovcnt; i++) { + len = spdk_min(iovs[i].iov_len, buf_left); + buf_left -= len; + memcpy(iovs[i].iov_base, pos, len); + pos += len; + } + + return buf_len; +} + +void * +spdk_scsi_task_gather_data(struct spdk_scsi_task *task, int *len) +{ + int i; + struct iovec *iovs = task->iovs; + size_t buf_len = 0; + uint8_t *buf, *pos; + + for (i = 0; i < task->iovcnt; i++) { + assert(iovs[i].iov_base != NULL); + buf_len += iovs[i].iov_len; + } + + if (buf_len == 0) { + *len = 0; + return NULL; + } + + buf = calloc(1, buf_len); + if (buf == NULL) { + *len = -1; + return NULL; + } + + pos = buf; + for (i = 0; i < task->iovcnt; i++) { + memcpy(pos, iovs[i].iov_base, iovs[i].iov_len); + pos += iovs[i].iov_len; + } + + *len = buf_len; + return buf; +} + +void +spdk_scsi_task_set_data(struct spdk_scsi_task *task, void *data, uint32_t len) +{ + assert(task->iovcnt == 1); + assert(task->alloc_len == 0); + + task->iovs[0].iov_base = data; + task->iovs[0].iov_len = len; +} + +void +spdk_scsi_task_build_sense_data(struct spdk_scsi_task *task, int sk, int asc, int ascq) +{ + uint8_t *cp; + int resp_code; + + resp_code = 0x70; /* Current + Fixed format */ + + /* Sense Data */ + cp = task->sense_data; + + /* VALID(7) RESPONSE CODE(6-0) */ + cp[0] = 0x80 | resp_code; + /* Obsolete */ + cp[1] = 0; + /* FILEMARK(7) EOM(6) ILI(5) SENSE KEY(3-0) */ + cp[2] = sk & 0xf; + /* INFORMATION */ + memset(&cp[3], 0, 4); + + /* ADDITIONAL SENSE LENGTH */ + cp[7] = 10; + + /* COMMAND-SPECIFIC INFORMATION */ + memset(&cp[8], 0, 4); + /* ADDITIONAL SENSE CODE */ + cp[12] = asc; + /* ADDITIONAL SENSE CODE QUALIFIER */ + cp[13] = ascq; + /* FIELD REPLACEABLE UNIT CODE */ + cp[14] = 0; + + /* SKSV(7) SENSE KEY SPECIFIC(6-0,7-0,7-0) */ + cp[15] = 0; + cp[16] = 0; + cp[17] = 0; + + /* SenseLength */ + task->sense_data_len = 18; +} + +void +spdk_scsi_task_set_status(struct spdk_scsi_task *task, int sc, int sk, + int asc, int ascq) +{ + if (sc == SPDK_SCSI_STATUS_CHECK_CONDITION) { + spdk_scsi_task_build_sense_data(task, sk, asc, ascq); + } + task->status = sc; +} + +void +spdk_scsi_task_copy_status(struct spdk_scsi_task *dst, + struct spdk_scsi_task *src) +{ + memcpy(dst->sense_data, src->sense_data, src->sense_data_len); + dst->sense_data_len = src->sense_data_len; + dst->status = src->status; +} + +void +spdk_scsi_task_process_null_lun(struct spdk_scsi_task *task) +{ + uint8_t buffer[36]; + uint32_t allocation_len; + uint32_t data_len; + + task->length = task->transfer_len; + if (task->cdb[0] == SPDK_SPC_INQUIRY) { + /* + * SPC-4 states that INQUIRY commands to an unsupported LUN + * must be served with PERIPHERAL QUALIFIER = 0x3 and + * PERIPHERAL DEVICE TYPE = 0x1F. + */ + data_len = sizeof(buffer); + + memset(buffer, 0, data_len); + /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */ + buffer[0] = 0x03 << 5 | 0x1f; + /* ADDITIONAL LENGTH */ + buffer[4] = data_len - 5; + + allocation_len = from_be16(&task->cdb[3]); + if (spdk_scsi_task_scatter_data(task, buffer, spdk_min(allocation_len, data_len)) >= 0) { + task->data_transferred = data_len; + task->status = SPDK_SCSI_STATUS_GOOD; + } + } else { + /* LOGICAL UNIT NOT SUPPORTED */ + spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION, + SPDK_SCSI_SENSE_ILLEGAL_REQUEST, + SPDK_SCSI_ASC_LOGICAL_UNIT_NOT_SUPPORTED, + SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE); + task->data_transferred = 0; + } +} + +void +spdk_scsi_task_process_abort(struct spdk_scsi_task *task) +{ + spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION, + SPDK_SCSI_SENSE_ABORTED_COMMAND, + SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE, + SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE); +} |