Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/share/examples/scsi_target/scsi_cmds.c
39476 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* SCSI Disk Emulator
5
*
6
* Copyright (c) 2002 Nate Lawson.
7
* All rights reserved.
8
*
9
* Redistribution and use in source and binary forms, with or without
10
* modification, are permitted provided that the following conditions
11
* are met:
12
* 1. Redistributions of source code must retain the above copyright
13
* notice, this list of conditions, and the following disclaimer,
14
* without modification, immediately at the beginning of the file.
15
* 2. The name of the author may not be used to endorse or promote products
16
* derived from this software without specific prior written permission.
17
*
18
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
22
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28
* SUCH DAMAGE.
29
*/
30
31
#include <stdio.h>
32
#include <stddef.h>
33
#include <stdarg.h>
34
#include <stdlib.h>
35
#include <string.h>
36
#include <err.h>
37
#include <aio.h>
38
#include <unistd.h>
39
#include <assert.h>
40
#include <sys/param.h>
41
#include <sys/types.h>
42
43
#include <cam/cam.h>
44
#include <cam/cam_ccb.h>
45
#include <cam/scsi/scsi_all.h>
46
#include <cam/scsi/scsi_targetio.h>
47
#include "scsi_target.h"
48
49
typedef int targ_start_func(struct ccb_accept_tio *, struct ccb_scsiio *);
50
typedef void targ_done_func(struct ccb_accept_tio *, struct ccb_scsiio *,
51
io_ops);
52
#ifndef REPORT_LUNS
53
#define REPORT_LUNS 0xa0
54
#endif
55
56
struct targ_cdb_handlers {
57
u_int8_t cmd;
58
targ_start_func *start;
59
targ_done_func *done;
60
#define ILLEGAL_CDB 0xFF
61
};
62
63
static targ_start_func tcmd_inquiry;
64
static targ_start_func tcmd_req_sense;
65
static targ_start_func tcmd_rd_cap;
66
#ifdef READ_16
67
static targ_start_func tcmd_rd_cap16;
68
#endif
69
static targ_start_func tcmd_rdwr;
70
static targ_start_func tcmd_rdwr_decode;
71
static targ_done_func tcmd_rdwr_done;
72
static targ_start_func tcmd_null_ok;
73
static targ_start_func tcmd_illegal_req;
74
static int start_io(struct ccb_accept_tio *atio,
75
struct ccb_scsiio *ctio, int dir);
76
static int init_inquiry(u_int16_t req_flags, u_int16_t sim_flags);
77
static struct initiator_state *
78
tcmd_get_istate(u_int init_id);
79
static void cdb_debug(u_int8_t *cdb, const char *msg, ...);
80
81
static struct targ_cdb_handlers cdb_handlers[] = {
82
{ READ_10, tcmd_rdwr, tcmd_rdwr_done },
83
{ WRITE_10, tcmd_rdwr, tcmd_rdwr_done },
84
{ READ_6, tcmd_rdwr, tcmd_rdwr_done },
85
{ WRITE_6, tcmd_rdwr, tcmd_rdwr_done },
86
{ INQUIRY, tcmd_inquiry, NULL },
87
{ REQUEST_SENSE, tcmd_req_sense, NULL },
88
{ READ_CAPACITY, tcmd_rd_cap, NULL },
89
{ TEST_UNIT_READY, tcmd_null_ok, NULL },
90
{ START_STOP_UNIT, tcmd_null_ok, NULL },
91
{ SYNCHRONIZE_CACHE, tcmd_null_ok, NULL },
92
{ MODE_SENSE_6, tcmd_illegal_req, NULL },
93
{ MODE_SELECT_6, tcmd_illegal_req, NULL },
94
{ REPORT_LUNS, tcmd_illegal_req, NULL },
95
#ifdef READ_16
96
{ READ_16, tcmd_rdwr, tcmd_rdwr_done },
97
{ WRITE_16, tcmd_rdwr, tcmd_rdwr_done },
98
{ SERVICE_ACTION_IN, tcmd_rd_cap16, NULL },
99
#endif
100
{ ILLEGAL_CDB, NULL, NULL }
101
};
102
103
static struct scsi_inquiry_data inq_data;
104
static struct initiator_state istates[MAX_INITIATORS];
105
106
cam_status
107
tcmd_init(u_int16_t req_inq_flags, u_int16_t sim_inq_flags)
108
{
109
struct initiator_state *istate;
110
int i, ret;
111
112
/* Initialize our inquiry data */
113
ret = init_inquiry(req_inq_flags, sim_inq_flags);
114
if (ret != 0)
115
return (ret);
116
117
/* We start out life with a UA to indicate power-on/reset. */
118
for (i = 0; i < MAX_INITIATORS; i++) {
119
istate = tcmd_get_istate(i);
120
bzero(istate, sizeof(*istate));
121
istate->pending_ua = UA_POWER_ON;
122
}
123
124
return (0);
125
}
126
127
/* Caller allocates CTIO, sets its init_id
128
return 0 if done, 1 if more processing needed
129
on 0, caller sets SEND_STATUS */
130
int
131
tcmd_handle(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio, io_ops event)
132
{
133
static struct targ_cdb_handlers *last_cmd;
134
struct initiator_state *istate;
135
struct atio_descr *a_descr;
136
int ret;
137
138
if (debug) {
139
warnx("tcmd_handle atio %p ctio %p atioflags %#x", atio, ctio,
140
atio->ccb_h.flags);
141
}
142
ret = 0;
143
a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
144
145
/* Do a full lookup if one-behind cache failed */
146
if (last_cmd == NULL || last_cmd->cmd != a_descr->cdb[0]) {
147
struct targ_cdb_handlers *h;
148
149
for (h = cdb_handlers; h->cmd != ILLEGAL_CDB; h++) {
150
if (a_descr->cdb[0] == h->cmd)
151
break;
152
}
153
last_cmd = h;
154
}
155
156
/* call completion and exit */
157
if (event != ATIO_WORK) {
158
if (last_cmd->done != NULL)
159
last_cmd->done(atio, ctio, event);
160
else
161
free_ccb((union ccb *)ctio);
162
return (1);
163
}
164
165
if (last_cmd->cmd == ILLEGAL_CDB) {
166
if (event != ATIO_WORK) {
167
warnx("no done func for %#x???", a_descr->cdb[0]);
168
abort();
169
}
170
/* Not found, return illegal request */
171
warnx("cdb %#x not handled", a_descr->cdb[0]);
172
tcmd_illegal_req(atio, ctio);
173
send_ccb((union ccb *)ctio, /*priority*/1);
174
return (0);
175
}
176
177
istate = tcmd_get_istate(ctio->init_id);
178
if (istate == NULL) {
179
tcmd_illegal_req(atio, ctio);
180
send_ccb((union ccb *)ctio, /*priority*/1);
181
return (0);
182
}
183
184
if (istate->pending_ca == 0 && istate->pending_ua != 0 &&
185
a_descr->cdb[0] != INQUIRY) {
186
tcmd_sense(ctio->init_id, ctio, SSD_KEY_UNIT_ATTENTION,
187
0x29, istate->pending_ua == UA_POWER_ON ? 1 : 2);
188
istate->pending_ca = CA_UNIT_ATTN;
189
if (debug) {
190
cdb_debug(a_descr->cdb, "UA active for %u: ",
191
atio->init_id);
192
}
193
send_ccb((union ccb *)ctio, /*priority*/1);
194
return (0);
195
}
196
197
/* Store current CA and UA for later */
198
istate->orig_ua = istate->pending_ua;
199
istate->orig_ca = istate->pending_ca;
200
201
/*
202
* As per SAM2, any command that occurs
203
* after a CA is reported, clears the CA. We must
204
* also clear the UA condition, if any, that caused
205
* the CA to occur assuming the UA is not for a
206
* persistent condition.
207
*/
208
istate->pending_ca = CA_NONE;
209
if (istate->orig_ca == CA_UNIT_ATTN)
210
istate->pending_ua = UA_NONE;
211
212
/* If we have a valid handler, call start or completion function */
213
if (last_cmd->cmd != ILLEGAL_CDB) {
214
ret = last_cmd->start(atio, ctio);
215
/* XXX hack */
216
if (last_cmd->start != tcmd_rdwr) {
217
a_descr->init_req += ctio->dxfer_len;
218
send_ccb((union ccb *)ctio, /*priority*/1);
219
}
220
}
221
222
return (ret);
223
}
224
225
static struct initiator_state *
226
tcmd_get_istate(u_int init_id)
227
{
228
if (init_id >= MAX_INITIATORS) {
229
warnx("illegal init_id %d, max %d", init_id, MAX_INITIATORS - 1);
230
return (NULL);
231
} else {
232
return (&istates[init_id]);
233
}
234
}
235
236
void
237
tcmd_sense(u_int init_id, struct ccb_scsiio *ctio, u_int8_t flags,
238
u_int8_t asc, u_int8_t ascq)
239
{
240
struct initiator_state *istate;
241
struct scsi_sense_data_fixed *sense;
242
243
/* Set our initiator's istate */
244
istate = tcmd_get_istate(init_id);
245
if (istate == NULL)
246
return;
247
istate->pending_ca |= CA_CMD_SENSE; /* XXX set instead of or? */
248
sense = (struct scsi_sense_data_fixed *)&istate->sense_data;
249
bzero(sense, sizeof(*sense));
250
sense->error_code = SSD_CURRENT_ERROR;
251
sense->flags = flags;
252
sense->add_sense_code = asc;
253
sense->add_sense_code_qual = ascq;
254
sense->extra_len =
255
offsetof(struct scsi_sense_data_fixed, sense_key_spec[2]) -
256
offsetof(struct scsi_sense_data_fixed, extra_len);
257
258
/* Fill out the supplied CTIO */
259
if (ctio != NULL) {
260
bcopy(sense, &ctio->sense_data, sizeof(*sense));
261
ctio->sense_len = sizeof(*sense); /* XXX */
262
ctio->ccb_h.flags &= ~CAM_DIR_MASK;
263
ctio->ccb_h.flags |= CAM_DIR_NONE | CAM_SEND_SENSE |
264
CAM_SEND_STATUS;
265
ctio->dxfer_len = 0;
266
ctio->scsi_status = SCSI_STATUS_CHECK_COND;
267
}
268
}
269
270
void
271
tcmd_ua(u_int init_id, ua_types new_ua)
272
{
273
struct initiator_state *istate;
274
u_int start, end;
275
276
if (init_id == CAM_TARGET_WILDCARD) {
277
start = 0;
278
end = MAX_INITIATORS - 1;
279
} else {
280
start = end = init_id;
281
}
282
283
for (; start <= end; start++) {
284
istate = tcmd_get_istate(start);
285
if (istate == NULL)
286
break;
287
istate->pending_ua = new_ua;
288
}
289
}
290
291
static int
292
tcmd_inquiry(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio)
293
{
294
struct scsi_inquiry *inq;
295
struct atio_descr *a_descr;
296
struct initiator_state *istate;
297
struct scsi_sense_data_fixed *sense;
298
299
a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
300
inq = (struct scsi_inquiry *)a_descr->cdb;
301
302
if (debug)
303
cdb_debug(a_descr->cdb, "INQUIRY from %u: ", atio->init_id);
304
/*
305
* Validate the command. We don't support any VPD pages, so
306
* complain if EVPD or CMDDT is set.
307
*/
308
istate = tcmd_get_istate(ctio->init_id);
309
sense = (struct scsi_sense_data_fixed *)&istate->sense_data;
310
if ((inq->byte2 & SI_EVPD) != 0) {
311
tcmd_illegal_req(atio, ctio);
312
sense->sense_key_spec[0] = SSD_SCS_VALID | SSD_FIELDPTR_CMD |
313
SSD_BITPTR_VALID | /*bit value*/1;
314
sense->sense_key_spec[1] = 0;
315
sense->sense_key_spec[2] =
316
offsetof(struct scsi_inquiry, byte2);
317
} else if (inq->page_code != 0) {
318
tcmd_illegal_req(atio, ctio);
319
sense->sense_key_spec[0] = SSD_SCS_VALID | SSD_FIELDPTR_CMD;
320
sense->sense_key_spec[1] = 0;
321
sense->sense_key_spec[2] =
322
offsetof(struct scsi_inquiry, page_code);
323
} else {
324
bcopy(&inq_data, ctio->data_ptr, sizeof(inq_data));
325
ctio->dxfer_len = inq_data.additional_length + 4;
326
ctio->dxfer_len = min(ctio->dxfer_len,
327
scsi_2btoul(inq->length));
328
ctio->ccb_h.flags |= CAM_DIR_IN | CAM_SEND_STATUS;
329
ctio->scsi_status = SCSI_STATUS_OK;
330
}
331
return (0);
332
}
333
334
/* Initialize the inquiry response structure with the requested flags */
335
static int
336
init_inquiry(u_int16_t req_flags, u_int16_t sim_flags)
337
{
338
struct scsi_inquiry_data *inq;
339
340
inq = &inq_data;
341
bzero(inq, sizeof(*inq));
342
inq->device = T_DIRECT | (SID_QUAL_LU_CONNECTED << 5);
343
#ifdef SCSI_REV_SPC
344
inq->version = SCSI_REV_SPC; /* was 2 */
345
#else
346
inq->version = SCSI_REV_3; /* was 2 */
347
#endif
348
349
/*
350
* XXX cpi.hba_inquiry doesn't support Addr16 so we give the
351
* user what they want if they ask for it.
352
*/
353
if ((req_flags & SID_Addr16) != 0) {
354
sim_flags |= SID_Addr16;
355
warnx("Not sure SIM supports Addr16 but enabling it anyway");
356
}
357
358
/* Advertise only what the SIM can actually support */
359
req_flags &= sim_flags;
360
scsi_ulto2b(req_flags, &inq->spc2_flags);
361
362
inq->response_format = 2; /* SCSI2 Inquiry Format */
363
inq->additional_length = SHORT_INQUIRY_LENGTH -
364
offsetof(struct scsi_inquiry_data, additional_length);
365
bcopy("FreeBSD ", inq->vendor, SID_VENDOR_SIZE);
366
bcopy("Emulated Disk ", inq->product, SID_PRODUCT_SIZE);
367
bcopy("0.1 ", inq->revision, SID_REVISION_SIZE);
368
return (0);
369
}
370
371
static int
372
tcmd_req_sense(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio)
373
{
374
struct scsi_request_sense *rsense;
375
struct scsi_sense_data_fixed *sense;
376
struct initiator_state *istate;
377
size_t dlen;
378
struct atio_descr *a_descr;
379
380
a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
381
rsense = (struct scsi_request_sense *)a_descr->cdb;
382
383
istate = tcmd_get_istate(ctio->init_id);
384
sense = (struct scsi_sense_data_fixed *)&istate->sense_data;
385
386
if (debug) {
387
cdb_debug(a_descr->cdb, "REQ SENSE from %u: ", atio->init_id);
388
warnx("Sending sense: %#x %#x %#x", sense->flags,
389
sense->add_sense_code, sense->add_sense_code_qual);
390
}
391
392
if (istate->orig_ca == 0) {
393
tcmd_sense(ctio->init_id, NULL, SSD_KEY_NO_SENSE, 0, 0);
394
warnx("REQUEST SENSE from %u but no pending CA!",
395
ctio->init_id);
396
}
397
398
bcopy(sense, ctio->data_ptr, sizeof(struct scsi_sense_data));
399
dlen = offsetof(struct scsi_sense_data_fixed, extra_len) +
400
sense->extra_len + 1;
401
ctio->dxfer_len = min(dlen, SCSI_CDB6_LEN(rsense->length));
402
ctio->ccb_h.flags |= CAM_DIR_IN | CAM_SEND_STATUS;
403
ctio->scsi_status = SCSI_STATUS_OK;
404
return (0);
405
}
406
407
static int
408
tcmd_rd_cap(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio)
409
{
410
struct scsi_read_capacity_data *srp;
411
struct atio_descr *a_descr;
412
uint32_t vsize;
413
414
a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
415
srp = (struct scsi_read_capacity_data *)ctio->data_ptr;
416
417
if (volume_size > 0xffffffff)
418
vsize = 0xffffffff;
419
else
420
vsize = (uint32_t)(volume_size - 1);
421
422
if (debug) {
423
cdb_debug(a_descr->cdb, "READ CAP from %u (%u, %u): ",
424
atio->init_id, vsize, sector_size);
425
}
426
427
bzero(srp, sizeof(*srp));
428
scsi_ulto4b(vsize, srp->addr);
429
scsi_ulto4b(sector_size, srp->length);
430
431
ctio->dxfer_len = sizeof(*srp);
432
ctio->ccb_h.flags |= CAM_DIR_IN | CAM_SEND_STATUS;
433
ctio->scsi_status = SCSI_STATUS_OK;
434
return (0);
435
}
436
437
#ifdef READ_16
438
static int
439
tcmd_rd_cap16(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio)
440
{
441
struct scsi_read_capacity_16 *scsi_cmd;
442
struct scsi_read_capacity_data_long *srp;
443
struct atio_descr *a_descr;
444
445
a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
446
scsi_cmd = (struct scsi_read_capacity_16 *)a_descr->cdb;
447
srp = (struct scsi_read_capacity_data_long *)ctio->data_ptr;
448
449
if (scsi_cmd->service_action != SRC16_SERVICE_ACTION) {
450
tcmd_illegal_req(atio, ctio);
451
return (0);
452
}
453
454
if (debug) {
455
cdb_debug(a_descr->cdb, "READ CAP16 from %u (%u, %u): ",
456
atio->init_id, volume_size - 1, sector_size);
457
}
458
459
bzero(srp, sizeof(*srp));
460
scsi_u64to8b(volume_size - 1, srp->addr);
461
scsi_ulto4b(sector_size, srp->length);
462
463
ctio->dxfer_len = sizeof(*srp);
464
ctio->ccb_h.flags |= CAM_DIR_IN | CAM_SEND_STATUS;
465
ctio->scsi_status = SCSI_STATUS_OK;
466
return (0);
467
}
468
#endif
469
470
static int
471
tcmd_rdwr(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio)
472
{
473
struct atio_descr *a_descr;
474
struct ctio_descr *c_descr;
475
int ret;
476
477
a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
478
c_descr = (struct ctio_descr *)ctio->ccb_h.targ_descr;
479
480
/* Command needs to be decoded */
481
if ((a_descr->flags & CAM_DIR_MASK) == CAM_DIR_BOTH) {
482
if (debug)
483
warnx("Calling rdwr_decode");
484
ret = tcmd_rdwr_decode(atio, ctio);
485
if (ret == 0) {
486
send_ccb((union ccb *)ctio, /*priority*/1);
487
return (0);
488
}
489
}
490
ctio->ccb_h.flags |= a_descr->flags;
491
492
/* Call appropriate work function */
493
if ((a_descr->flags & CAM_DIR_IN) != 0) {
494
ret = start_io(atio, ctio, CAM_DIR_IN);
495
if (debug)
496
warnx("Starting %p DIR_IN @" OFF_FMT ":%u",
497
a_descr, c_descr->offset, a_descr->targ_req);
498
} else {
499
ret = start_io(atio, ctio, CAM_DIR_OUT);
500
if (debug)
501
warnx("Starting %p DIR_OUT @" OFF_FMT ":%u",
502
a_descr, c_descr->offset, a_descr->init_req);
503
}
504
505
return (ret);
506
}
507
508
static int
509
tcmd_rdwr_decode(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio)
510
{
511
uint64_t blkno;
512
uint32_t count;
513
struct atio_descr *a_descr;
514
u_int8_t *cdb;
515
516
a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
517
cdb = a_descr->cdb;
518
if (debug)
519
cdb_debug(cdb, "R/W from %u: ", atio->init_id);
520
521
switch (cdb[0]) {
522
case READ_6:
523
case WRITE_6:
524
{
525
struct scsi_rw_6 *rw_6 = (struct scsi_rw_6 *)cdb;
526
blkno = scsi_3btoul(rw_6->addr);
527
count = rw_6->length;
528
break;
529
}
530
case READ_10:
531
case WRITE_10:
532
{
533
struct scsi_rw_10 *rw_10 = (struct scsi_rw_10 *)cdb;
534
blkno = scsi_4btoul(rw_10->addr);
535
count = scsi_2btoul(rw_10->length);
536
break;
537
}
538
#ifdef READ_16
539
case READ_16:
540
case WRITE_16:
541
{
542
struct scsi_rw_16 *rw_16 = (struct scsi_rw_16 *)cdb;
543
blkno = scsi_8btou64(rw_16->addr);
544
count = scsi_4btoul(rw_16->length);
545
break;
546
}
547
#endif
548
default:
549
tcmd_illegal_req(atio, ctio);
550
return (0);
551
}
552
if (((off_t)(blkno + count)) > volume_size) {
553
warnx("Attempt to access past end of volume");
554
tcmd_sense(ctio->init_id, ctio,
555
SSD_KEY_ILLEGAL_REQUEST, 0x21, 0);
556
return (0);
557
}
558
559
/* Get an (overall) data length and set direction */
560
a_descr->base_off = ((off_t)blkno) * sector_size;
561
a_descr->total_len = count * sector_size;
562
if (a_descr->total_len == 0) {
563
if (debug)
564
warnx("r/w 0 blocks @ blkno " OFF_FMT, blkno);
565
tcmd_null_ok(atio, ctio);
566
return (0);
567
} else if (cdb[0] == WRITE_6 || cdb[0] == WRITE_10) {
568
a_descr->flags |= CAM_DIR_OUT;
569
if (debug)
570
warnx("write %u blocks @ blkno " OFF_FMT, count, blkno);
571
} else {
572
a_descr->flags |= CAM_DIR_IN;
573
if (debug)
574
warnx("read %u blocks @ blkno " OFF_FMT, count, blkno);
575
}
576
return (1);
577
}
578
579
static int
580
start_io(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio, int dir)
581
{
582
struct atio_descr *a_descr;
583
struct ctio_descr *c_descr;
584
int ret;
585
586
/* Set up common structures */
587
a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
588
c_descr = (struct ctio_descr *)ctio->ccb_h.targ_descr;
589
590
if (dir == CAM_DIR_IN) {
591
c_descr->offset = a_descr->base_off + a_descr->targ_req;
592
ctio->dxfer_len = a_descr->total_len - a_descr->targ_req;
593
} else {
594
c_descr->offset = a_descr->base_off + a_descr->init_req;
595
ctio->dxfer_len = a_descr->total_len - a_descr->init_req;
596
}
597
ctio->dxfer_len = min(ctio->dxfer_len, buf_size);
598
assert(ctio->dxfer_len >= 0);
599
600
c_descr->aiocb.aio_offset = c_descr->offset;
601
c_descr->aiocb.aio_nbytes = ctio->dxfer_len;
602
603
/* If DIR_IN, start read from target, otherwise begin CTIO xfer. */
604
ret = 1;
605
if (dir == CAM_DIR_IN) {
606
if (notaio) {
607
if (debug)
608
warnx("read sync %lu @ block " OFF_FMT,
609
(unsigned long)
610
(ctio->dxfer_len / sector_size),
611
c_descr->offset / sector_size);
612
if (lseek(c_descr->aiocb.aio_fildes,
613
c_descr->aiocb.aio_offset, SEEK_SET) < 0) {
614
perror("lseek");
615
err(1, "lseek");
616
}
617
if (read(c_descr->aiocb.aio_fildes,
618
(void *)c_descr->aiocb.aio_buf,
619
ctio->dxfer_len) != ctio->dxfer_len) {
620
err(1, "read");
621
}
622
} else {
623
if (debug)
624
warnx("read async %lu @ block " OFF_FMT,
625
(unsigned long)
626
(ctio->dxfer_len / sector_size),
627
c_descr->offset / sector_size);
628
if (aio_read(&c_descr->aiocb) < 0) {
629
err(1, "aio_read"); /* XXX */
630
}
631
}
632
a_descr->targ_req += ctio->dxfer_len;
633
/* if we're done, we can mark the CCB as to send status */
634
if (a_descr->targ_req == a_descr->total_len) {
635
ctio->ccb_h.flags |= CAM_SEND_STATUS;
636
ctio->scsi_status = SCSI_STATUS_OK;
637
ret = 0;
638
}
639
if (notaio)
640
tcmd_rdwr_done(atio, ctio, AIO_DONE);
641
} else {
642
if (a_descr->targ_ack == a_descr->total_len)
643
tcmd_null_ok(atio, ctio);
644
a_descr->init_req += ctio->dxfer_len;
645
if (a_descr->init_req == a_descr->total_len &&
646
ctio->dxfer_len > 0) {
647
/*
648
* If data phase done, remove atio from workq.
649
* The completion handler will call work_atio to
650
* send the final status.
651
*/
652
ret = 0;
653
}
654
send_ccb((union ccb *)ctio, /*priority*/1);
655
}
656
657
return (ret);
658
}
659
660
static void
661
tcmd_rdwr_done(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio,
662
io_ops event)
663
{
664
struct atio_descr *a_descr;
665
struct ctio_descr *c_descr;
666
667
a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
668
c_descr = (struct ctio_descr *)ctio->ccb_h.targ_descr;
669
670
switch (event) {
671
case AIO_DONE:
672
if (!notaio && aio_return(&c_descr->aiocb) < 0) {
673
warn("aio_return error");
674
/* XXX */
675
tcmd_sense(ctio->init_id, ctio,
676
SSD_KEY_MEDIUM_ERROR, 0, 0);
677
send_ccb((union ccb *)ctio, /*priority*/1);
678
break;
679
}
680
a_descr->targ_ack += ctio->dxfer_len;
681
if ((a_descr->flags & CAM_DIR_IN) != 0) {
682
if (debug) {
683
if (notaio)
684
warnx("sending CTIO for AIO read");
685
else
686
warnx("sending CTIO for sync read");
687
}
688
a_descr->init_req += ctio->dxfer_len;
689
send_ccb((union ccb *)ctio, /*priority*/1);
690
} else {
691
/* Use work function to send final status */
692
if (a_descr->init_req == a_descr->total_len)
693
work_atio(atio);
694
if (debug)
695
warnx("AIO done freeing CTIO");
696
free_ccb((union ccb *)ctio);
697
}
698
break;
699
case CTIO_DONE:
700
switch (ctio->ccb_h.status & CAM_STATUS_MASK) {
701
case CAM_REQ_CMP:
702
break;
703
case CAM_REQUEUE_REQ:
704
warnx("requeueing request");
705
if ((a_descr->flags & CAM_DIR_MASK) == CAM_DIR_OUT) {
706
if (aio_write(&c_descr->aiocb) < 0) {
707
err(1, "aio_write"); /* XXX */
708
}
709
} else {
710
if (aio_read(&c_descr->aiocb) < 0) {
711
err(1, "aio_read"); /* XXX */
712
}
713
}
714
return;
715
default:
716
errx(1, "CTIO failed, status %#x", ctio->ccb_h.status);
717
}
718
a_descr->init_ack += ctio->dxfer_len;
719
if ((a_descr->flags & CAM_DIR_MASK) == CAM_DIR_OUT &&
720
ctio->dxfer_len > 0) {
721
a_descr->targ_req += ctio->dxfer_len;
722
if (notaio) {
723
if (debug)
724
warnx("write sync %lu @ block "
725
OFF_FMT, (unsigned long)
726
(ctio->dxfer_len / sector_size),
727
c_descr->offset / sector_size);
728
if (lseek(c_descr->aiocb.aio_fildes,
729
c_descr->aiocb.aio_offset, SEEK_SET) < 0) {
730
perror("lseek");
731
err(1, "lseek");
732
}
733
if (write(c_descr->aiocb.aio_fildes,
734
(void *) c_descr->aiocb.aio_buf,
735
ctio->dxfer_len) != ctio->dxfer_len) {
736
err(1, "write");
737
}
738
tcmd_rdwr_done(atio, ctio, AIO_DONE);
739
} else {
740
if (debug)
741
warnx("write async %lu @ block "
742
OFF_FMT, (unsigned long)
743
(ctio->dxfer_len / sector_size),
744
c_descr->offset / sector_size);
745
if (aio_write(&c_descr->aiocb) < 0) {
746
err(1, "aio_write"); /* XXX */
747
}
748
}
749
} else {
750
if (debug)
751
warnx("CTIO done freeing CTIO");
752
free_ccb((union ccb *)ctio);
753
}
754
break;
755
default:
756
warnx("Unknown completion code %d", event);
757
abort();
758
/* NOTREACHED */
759
}
760
}
761
762
/* Simple ok message used by TUR, SYNC_CACHE, etc. */
763
static int
764
tcmd_null_ok(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio)
765
{
766
if (debug) {
767
struct atio_descr *a_descr;
768
769
a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
770
cdb_debug(a_descr->cdb, "Sending null ok to %u : ", atio->init_id);
771
}
772
773
ctio->dxfer_len = 0;
774
ctio->ccb_h.flags &= ~CAM_DIR_MASK;
775
ctio->ccb_h.flags |= CAM_DIR_NONE | CAM_SEND_STATUS;
776
ctio->scsi_status = SCSI_STATUS_OK;
777
return (0);
778
}
779
780
/* Simple illegal request message used by MODE SENSE, etc. */
781
static int
782
tcmd_illegal_req(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio)
783
{
784
if (debug) {
785
struct atio_descr *a_descr;
786
787
a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
788
cdb_debug(a_descr->cdb, "Sending ill req to %u: ", atio->init_id);
789
}
790
791
tcmd_sense(atio->init_id, ctio, SSD_KEY_ILLEGAL_REQUEST,
792
/*asc*/0x24, /*ascq*/0);
793
return (0);
794
}
795
796
static void
797
cdb_debug(u_int8_t *cdb, const char *msg, ...)
798
{
799
char msg_buf[512];
800
int len;
801
va_list ap;
802
803
va_start(ap, msg);
804
vsnprintf(msg_buf, sizeof(msg_buf), msg, ap);
805
va_end(ap);
806
len = strlen(msg_buf);
807
scsi_cdb_string(cdb, msg_buf + len, sizeof(msg_buf) - len);
808
warnx("%s", msg_buf);
809
}
810
811