1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright (C) 2016 Intel Corporation
3 * All rights reserved.
4 */
5
6 #include "iscsi/task.h"
7 #include "iscsi/iscsi.h"
8 #include "iscsi/conn.h"
9
10 #include "spdk/env.h"
11 #include "spdk/sock.h"
12 #include "spdk_internal/cunit.h"
13
14 #include "spdk/log.h"
15 #include "spdk_internal/mock.h"
16
17 #include "scsi/scsi_internal.h"
18
19 SPDK_LOG_REGISTER_COMPONENT(iscsi)
20
21 TAILQ_HEAD(, spdk_iscsi_pdu) g_write_pdu_list = TAILQ_HEAD_INITIALIZER(g_write_pdu_list);
22
23 static bool g_task_pool_is_empty = false;
24 static bool g_pdu_pool_is_empty = false;
25 static uint32_t g_conn_read_len;
26 static bool g_conn_read_data_digest = false;
27 static uint32_t g_data_digest;
28
29 struct spdk_iscsi_task *
iscsi_task_get(struct spdk_iscsi_conn * conn,struct spdk_iscsi_task * parent,spdk_scsi_task_cpl cpl_fn)30 iscsi_task_get(struct spdk_iscsi_conn *conn,
31 struct spdk_iscsi_task *parent,
32 spdk_scsi_task_cpl cpl_fn)
33 {
34 struct spdk_iscsi_task *task;
35
36 if (g_task_pool_is_empty) {
37 return NULL;
38 }
39
40 task = calloc(1, sizeof(*task));
41 if (!task) {
42 return NULL;
43 }
44
45 task->conn = conn;
46 task->scsi.cpl_fn = cpl_fn;
47 if (parent) {
48 parent->scsi.ref++;
49 task->parent = parent;
50 task->tag = parent->tag;
51 task->lun_id = parent->lun_id;
52 task->scsi.dxfer_dir = parent->scsi.dxfer_dir;
53 task->scsi.transfer_len = parent->scsi.transfer_len;
54 task->scsi.lun = parent->scsi.lun;
55 task->scsi.cdb = parent->scsi.cdb;
56 task->scsi.target_port = parent->scsi.target_port;
57 task->scsi.initiator_port = parent->scsi.initiator_port;
58 if (conn && (task->scsi.dxfer_dir == SPDK_SCSI_DIR_FROM_DEV)) {
59 conn->data_in_cnt++;
60 }
61 }
62
63 task->scsi.iovs = &task->scsi.iov;
64 return task;
65 }
66
67 void
spdk_scsi_task_put(struct spdk_scsi_task * task)68 spdk_scsi_task_put(struct spdk_scsi_task *task)
69 {
70 free(task);
71 }
72
73 void
iscsi_put_pdu(struct spdk_iscsi_pdu * pdu)74 iscsi_put_pdu(struct spdk_iscsi_pdu *pdu)
75 {
76 if (!pdu) {
77 return;
78 }
79
80 pdu->ref--;
81 if (pdu->ref < 0) {
82 CU_FAIL("negative ref count");
83 pdu->ref = 0;
84 }
85
86 if (pdu->ref == 0) {
87 if (pdu->data && !pdu->data_from_mempool) {
88 free(pdu->data);
89 }
90 free(pdu);
91 }
92 }
93
94 struct spdk_iscsi_pdu *
iscsi_get_pdu(struct spdk_iscsi_conn * conn)95 iscsi_get_pdu(struct spdk_iscsi_conn *conn)
96 {
97 struct spdk_iscsi_pdu *pdu;
98
99 assert(conn != NULL);
100 if (g_pdu_pool_is_empty) {
101 return NULL;
102 }
103
104 pdu = malloc(sizeof(*pdu));
105 if (!pdu) {
106 return NULL;
107 }
108
109 memset(pdu, 0, offsetof(struct spdk_iscsi_pdu, ahs));
110 pdu->ref = 1;
111 pdu->conn = conn;
112
113 return pdu;
114 }
115
116 DEFINE_STUB_V(spdk_scsi_task_process_null_lun, (struct spdk_scsi_task *task));
117
118 DEFINE_STUB_V(spdk_scsi_task_process_abort, (struct spdk_scsi_task *task));
119
120 void
spdk_scsi_dev_queue_task(struct spdk_scsi_dev * dev,struct spdk_scsi_task * task)121 spdk_scsi_dev_queue_task(struct spdk_scsi_dev *dev, struct spdk_scsi_task *task)
122 {
123 struct spdk_scsi_lun *lun;
124
125 lun = TAILQ_FIRST(&dev->luns);
126 SPDK_CU_ASSERT_FATAL(lun != NULL);
127
128 TAILQ_INSERT_TAIL(&lun->tasks, task, scsi_link);
129 }
130
131 DEFINE_STUB(spdk_scsi_dev_find_port_by_id, struct spdk_scsi_port *,
132 (struct spdk_scsi_dev *dev, uint64_t id), NULL);
133
134 DEFINE_STUB_V(spdk_scsi_dev_queue_mgmt_task,
135 (struct spdk_scsi_dev *dev, struct spdk_scsi_task *task));
136
137 const char *
spdk_scsi_dev_get_name(const struct spdk_scsi_dev * dev)138 spdk_scsi_dev_get_name(const struct spdk_scsi_dev *dev)
139 {
140 if (dev != NULL) {
141 return dev->name;
142 }
143
144 return NULL;
145 }
146
147 DEFINE_STUB(spdk_scsi_dev_construct, struct spdk_scsi_dev *,
148 (const char *name, const char **bdev_name_list,
149 int *lun_id_list, int num_luns, uint8_t protocol_id,
150 void (*hotremove_cb)(const struct spdk_scsi_lun *, void *),
151 void *hotremove_ctx),
152 NULL);
153
154 DEFINE_STUB_V(spdk_scsi_dev_destruct,
155 (struct spdk_scsi_dev *dev, spdk_scsi_dev_destruct_cb_t cb_fn, void *cb_arg));
156
157 DEFINE_STUB(spdk_scsi_dev_add_port, int,
158 (struct spdk_scsi_dev *dev, uint64_t id, const char *name), 0);
159
160 DEFINE_STUB(iscsi_drop_conns, int,
161 (struct spdk_iscsi_conn *conn, const char *conn_match, int drop_all),
162 0);
163
164 DEFINE_STUB(spdk_scsi_dev_delete_port, int,
165 (struct spdk_scsi_dev *dev, uint64_t id), 0);
166
167 DEFINE_STUB_V(shutdown_iscsi_conns, (void));
168
169 DEFINE_STUB_V(iscsi_conns_request_logout, (struct spdk_iscsi_tgt_node *target, int pg_tag));
170
171 DEFINE_STUB(iscsi_get_active_conns, int, (struct spdk_iscsi_tgt_node *target), 0);
172
173 void
iscsi_task_cpl(struct spdk_scsi_task * scsi_task)174 iscsi_task_cpl(struct spdk_scsi_task *scsi_task)
175 {
176 struct spdk_iscsi_task *iscsi_task;
177
178 if (scsi_task != NULL) {
179 iscsi_task = iscsi_task_from_scsi_task(scsi_task);
180 if (iscsi_task->parent && (iscsi_task->scsi.dxfer_dir == SPDK_SCSI_DIR_FROM_DEV)) {
181 assert(iscsi_task->conn->data_in_cnt > 0);
182 iscsi_task->conn->data_in_cnt--;
183 }
184
185 free(iscsi_task);
186 }
187 }
188
189 DEFINE_STUB_V(iscsi_task_mgmt_cpl, (struct spdk_scsi_task *scsi_task));
190
191 #define MAKE_DIGEST_WORD(BUF, CRC32C) \
192 ( ((*((uint8_t *)(BUF)+0)) = (uint8_t)((uint32_t)(CRC32C) >> 0)), \
193 ((*((uint8_t *)(BUF)+1)) = (uint8_t)((uint32_t)(CRC32C) >> 8)), \
194 ((*((uint8_t *)(BUF)+2)) = (uint8_t)((uint32_t)(CRC32C) >> 16)), \
195 ((*((uint8_t *)(BUF)+3)) = (uint8_t)((uint32_t)(CRC32C) >> 24)))
196
197 int
iscsi_conn_read_data(struct spdk_iscsi_conn * conn,int bytes,void * buf)198 iscsi_conn_read_data(struct spdk_iscsi_conn *conn, int bytes, void *buf)
199 {
200 uint32_t *data = buf;
201 int i;
202
203 if (g_conn_read_data_digest) {
204 MAKE_DIGEST_WORD(buf, g_data_digest);
205 return ISCSI_DIGEST_LEN;
206 }
207
208 /* Limit the length to 4 bytes multiples. */
209 SPDK_CU_ASSERT_FATAL((bytes % 4) == 0);
210
211 for (i = 0; i < bytes; i += 4) {
212 data[i / 4] = g_conn_read_len + i;
213 }
214
215 g_conn_read_len += bytes;
216
217 return bytes;
218 }
219
220 int
iscsi_conn_readv_data(struct spdk_iscsi_conn * conn,struct iovec * iov,int iovcnt)221 iscsi_conn_readv_data(struct spdk_iscsi_conn *conn, struct iovec *iov, int iovcnt)
222 {
223 int i, len = 0;
224
225 for (i = 0; i < iovcnt; i++) {
226 len += iov[i].iov_len;
227 }
228
229 return len;
230 }
231
232 void
iscsi_conn_write_pdu(struct spdk_iscsi_conn * conn,struct spdk_iscsi_pdu * pdu,iscsi_conn_xfer_complete_cb cb_fn,void * cb_arg)233 iscsi_conn_write_pdu(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu,
234 iscsi_conn_xfer_complete_cb cb_fn, void *cb_arg)
235 {
236 TAILQ_INSERT_TAIL(&g_write_pdu_list, pdu, tailq);
237 }
238
239 DEFINE_STUB_V(iscsi_conn_logout, (struct spdk_iscsi_conn *conn));
240
241 DEFINE_STUB_V(spdk_scsi_task_set_status,
242 (struct spdk_scsi_task *task, int sc, int sk, int asc, int ascq));
243
244 void
spdk_scsi_task_set_data(struct spdk_scsi_task * task,void * data,uint32_t len)245 spdk_scsi_task_set_data(struct spdk_scsi_task *task, void *data, uint32_t len)
246 {
247 SPDK_CU_ASSERT_FATAL(task->iovs != NULL);
248 task->iovs[0].iov_base = data;
249 task->iovs[0].iov_len = len;
250 }
251