Deleted Added
full compact
scsi_target.c (73388) scsi_target.c (107178)
1/*
1/*
2 * Sample program to attach to the "targ" processor target, target mode
3 * peripheral driver and push or receive data.
2 * SCSI Disk Emulator
4 *
3 *
5 * Copyright (c) 1998 Justin T. Gibbs.
4 * Copyright (c) 2002 Nate Lawson.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions, and the following disclaimer,
13 * without modification, immediately at the beginning of the file.

--- 7 unchanged lines hidden (view full) ---

21 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions, and the following disclaimer,
12 * without modification, immediately at the beginning of the file.

--- 7 unchanged lines hidden (view full) ---

20 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
29 * $FreeBSD: head/share/examples/scsi_target/scsi_target.c 73388 2001-03-03 21:23:31Z mjacob $
28 * $FreeBSD: head/share/examples/scsi_target/scsi_target.c 107178 2002-11-22 22:55:51Z njl $
30 */
31
32#include <sys/types.h>
33#include <errno.h>
29 */
30
31#include <sys/types.h>
32#include <errno.h>
33#include <err.h>
34#include <fcntl.h>
34#include <fcntl.h>
35#include <paths.h>
36#include <poll.h>
37#include <signal.h>
38#include <stddef.h>
39#include <stdio.h>
40#include <stdlib.h>
35#include <signal.h>
36#include <stddef.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
41#include <sysexits.h>
42#include <unistd.h>
40#include <sysexits.h>
41#include <unistd.h>
43
42#include <aio.h>
43#include <sys/stat.h>
44#include <sys/queue.h>
45#include <sys/event.h>
46#include <sys/param.h>
47#include <cam/cam_queue.h>
44#include <cam/scsi/scsi_all.h>
48#include <cam/scsi/scsi_all.h>
45#include <cam/scsi/scsi_message.h>
46#include <cam/scsi/scsi_targetio.h>
49#include <cam/scsi/scsi_targetio.h>
50#include <cam/scsi/scsi_message.h>
51#include "scsi_target.h"
47
52
48char *appname;
49int ifd;
50char *ifilename;
51int ofd;
52char *ofilename;
53size_t bufsize = 64 * 1024;
54void *buf;
55char targdevname[80];
56int targctlfd;
57int targfd;
58int quit;
59int debug = 0;
60struct ioc_alloc_unit alloc_unit = {
53/* Maximum amount to transfer per CTIO */
54#define MAX_XFER MAXPHYS
55/* Maximum number of allocated CTIOs */
56#define MAX_CTIOS 32
57/* Maximum sector size for emulated volume */
58#define MAX_SECTOR 32768
59
60/* Global variables */
61int debug;
62u_int32_t volume_size;
63size_t sector_size;
64size_t buf_size;
65
66/* Local variables */
67static int targ_fd;
68static int kq_fd;
69static int file_fd;
70static int num_ctios;
71static struct ccb_queue pending_queue;
72static struct ccb_queue work_queue;
73static struct ioc_enable_lun ioc_enlun = {
61 CAM_BUS_WILDCARD,
62 CAM_TARGET_WILDCARD,
63 CAM_LUN_WILDCARD
64};
65
74 CAM_BUS_WILDCARD,
75 CAM_TARGET_WILDCARD,
76 CAM_LUN_WILDCARD
77};
78
66static void pump_events();
67static void cleanup();
68static void handle_exception();
69static void quit_handler();
70static void usage();
79/* Local functions */
80static void cleanup(void);
81static int init_ccbs(void);
82static void request_loop(void);
83static void handle_read(void);
84/* static int work_atio(struct ccb_accept_tio *); */
85static void queue_io(struct ccb_scsiio *);
86static void run_queue(struct ccb_accept_tio *);
87static int work_inot(struct ccb_immed_notify *);
88static struct ccb_scsiio *
89 get_ctio(void);
90/* static void free_ccb(union ccb *); */
91static cam_status get_sim_flags(u_int16_t *);
92static void rel_simq(void);
93static void abort_all_pending(void);
94static void usage(void);
71
72int
73main(int argc, char *argv[])
74{
95
96int
97main(int argc, char *argv[])
98{
75 int ch;
99 int ch, unit;
100 char *file_name, targname[16];
101 u_int16_t req_flags, sim_flags;
102 off_t user_size;
76
103
77 appname = *argv;
78 while ((ch = getopt(argc, argv, "i:o:p:t:l:d")) != -1) {
104 /* Initialize */
105 debug = 0;
106 req_flags = sim_flags = 0;
107 user_size = 0;
108 targ_fd = file_fd = kq_fd = -1;
109 num_ctios = 0;
110 sector_size = SECTOR_SIZE;
111 buf_size = DFLTPHYS;
112
113 /* Prepare resource pools */
114 TAILQ_INIT(&pending_queue);
115 TAILQ_INIT(&work_queue);
116
117 while ((ch = getopt(argc, argv, "AdSTb:c:s:W:")) != -1) {
79 switch(ch) {
118 switch(ch) {
80 case 'i':
81 if ((ifd = open(optarg, O_RDONLY)) == -1) {
82 perror(optarg);
83 exit(EX_NOINPUT);
84 }
85 ifilename = optarg;
119 case 'A':
120 req_flags |= SID_Addr16;
86 break;
121 break;
87 case 'o':
88 if ((ofd = open(optarg,
89 O_WRONLY|O_CREAT), 0600) == -1) {
90 perror(optarg);
91 exit(EX_CANTCREAT);
92 }
93 ofilename = optarg;
122 case 'd':
123 debug = 1;
94 break;
124 break;
95 case 'p':
96 alloc_unit.path_id = atoi(optarg);
125 case 'S':
126 req_flags |= SID_Sync;
97 break;
127 break;
98 case 't':
99 alloc_unit.target_id = atoi(optarg);
128 case 'T':
129 req_flags |= SID_CmdQue;
100 break;
130 break;
101 case 'l':
102 alloc_unit.lun_id = atoi(optarg);
131 case 'b':
132 buf_size = atoi(optarg);
133 if (buf_size < 256 || buf_size > MAX_XFER)
134 errx(1, "Unreasonable buf size: %s", optarg);
103 break;
135 break;
104 case 'd':
105 debug++;
136 case 'c':
137 sector_size = atoi(optarg);
138 if (sector_size < 512 || sector_size > MAX_SECTOR)
139 errx(1, "Unreasonable sector size: %s", optarg);
106 break;
140 break;
107 case '?':
141 case 's':
142 user_size = strtoll(optarg, (char **)NULL, /*base*/10);
143 if (user_size < 0)
144 errx(1, "Unreasonable volume size: %s", optarg);
145 break;
146 case 'W':
147 req_flags &= ~(SID_WBus16 | SID_WBus32);
148 switch (atoi(optarg)) {
149 case 8:
150 /* Leave req_flags zeroed */
151 break;
152 case 16:
153 req_flags |= SID_WBus16;
154 break;
155 case 32:
156 req_flags |= SID_WBus32;
157 break;
158 default:
159 warnx("Width %s not supported", optarg);
160 usage();
161 /* NOTREACHED */
162 }
163 break;
108 default:
109 usage();
110 /* NOTREACHED */
111 }
112 }
113 argc -= optind;
114 argv += optind;
164 default:
165 usage();
166 /* NOTREACHED */
167 }
168 }
169 argc -= optind;
170 argv += optind;
115
116 if (alloc_unit.path_id == CAM_BUS_WILDCARD
117 || alloc_unit.target_id == CAM_TARGET_WILDCARD
118 || alloc_unit.lun_id == CAM_LUN_WILDCARD) {
119 fprintf(stderr, "%s: Incomplete device path specifiled\n",
120 appname);
171
172 if (argc != 2)
121 usage();
173 usage();
122 /* NOTREACHED */
123 }
124
174
125 if (argc != 0) {
126 fprintf(stderr, "%s: Too many arguments\n", appname);
175 sscanf(argv[0], "%u:%u:%u", &ioc_enlun.path_id, &ioc_enlun.target_id,
176 &ioc_enlun.lun_id);
177 file_name = argv[1];
178
179 if (ioc_enlun.path_id == CAM_BUS_WILDCARD ||
180 ioc_enlun.target_id == CAM_TARGET_WILDCARD ||
181 ioc_enlun.lun_id == CAM_LUN_WILDCARD) {
182 warnx("Incomplete target path specified");
127 usage();
128 /* NOTREACHED */
129 }
183 usage();
184 /* NOTREACHED */
185 }
186 /* We don't support any vendor-specific commands */
187 ioc_enlun.grp6_len = 0;
188 ioc_enlun.grp7_len = 0;
130
189
131 /* Allocate a new instance */
132 if ((targctlfd = open("/dev/targ.ctl", O_RDWR)) == -1) {
133 perror("/dev/targ.ctl");
134 exit(EX_UNAVAILABLE);
135 }
190 /* Open backing store for IO */
191 file_fd = open(file_name, O_RDWR);
192 if (file_fd < 0)
193 err(1, "open backing store file");
136
194
137 if (ioctl(targctlfd, TARGCTLIOALLOCUNIT, &alloc_unit) == -1) {
138 perror("TARGCTLIOALLOCUNIT");
139 exit(EX_SOFTWARE);
195 /* Check backing store size or use the size user gave us */
196 if (user_size == 0) {
197 struct stat st;
198
199 if (fstat(file_fd, &st) < 0)
200 err(1, "fstat file");
201 volume_size = st.st_size / sector_size;
202 } else {
203 volume_size = user_size / sector_size;
140 }
204 }
205 if (volume_size <= 0)
206 errx(1, "volume must be larger than %d", sector_size);
141
207
142 snprintf(targdevname, sizeof(targdevname), "%starg%d", _PATH_DEV,
143 alloc_unit.unit);
208 /* Go through all the control devices and find one that isn't busy. */
209 unit = 0;
210 do {
211 snprintf(targname, sizeof(targname), "/dev/targ%d", unit++);
212 targ_fd = open(targname, O_RDWR);
213 } while (targ_fd < 0 && errno == EBUSY);
144
214
145 if ((targfd = open(targdevname, O_RDWR)) == -1) {
146 perror(targdevname);
147 ioctl(targctlfd, TARGCTLIOFREEUNIT, &alloc_unit);
148 exit(EX_NOINPUT);
149 }
150
151 if (ioctl(targfd, TARGIODEBUG, &debug) == -1) {
152 perror("TARGIODEBUG");
153 (void) ioctl(targctlfd, TARGCTLIOFREEUNIT, &alloc_unit);
154 exit(EX_SOFTWARE);
155 }
215 if (targ_fd < 0)
216 err(1, "Tried to open %d devices, none available", unit);
156
217
157 buf = malloc(bufsize);
218 /* The first three are handled by kevent() later */
219 signal(SIGHUP, SIG_IGN);
220 signal(SIGINT, SIG_IGN);
221 signal(SIGTERM, SIG_IGN);
222 signal(SIGPROF, SIG_IGN);
223 signal(SIGALRM, SIG_IGN);
224 signal(SIGSTOP, SIG_IGN);
225 signal(SIGTSTP, SIG_IGN);
158
226
159 if (buf == NULL) {
160 fprintf(stderr, "%s: Could not malloc I/O buffer", appname);
161 if (debug) {
162 debug = 0;
163 (void) ioctl(targfd, TARGIODEBUG, &debug);
164 }
165 (void) ioctl(targctlfd, TARGCTLIOFREEUNIT, &alloc_unit);
166 exit(EX_OSERR);
227 /* Register a cleanup handler to run when exiting */
228 atexit(cleanup);
229
230 /* Enable listening on the specified LUN */
231 if (ioctl(targ_fd, TARGIOCENABLE, &ioc_enlun) != 0)
232 err(1, "TARGIOCENABLE");
233
234 /* Enable debugging if requested */
235 if (debug) {
236 if (ioctl(targ_fd, TARGIOCDEBUG, &debug) != 0)
237 err(1, "TARGIOCDEBUG");
167 }
168
238 }
239
169 signal(SIGHUP, quit_handler);
170 signal(SIGINT, quit_handler);
171 signal(SIGTERM, quit_handler);
240 /* Set up inquiry data according to what SIM supports */
241 if (get_sim_flags(&sim_flags) != CAM_REQ_CMP)
242 errx(1, "get_sim_flags");
243 if (tcmd_init(req_flags, sim_flags) != 0)
244 errx(1, "Initializing tcmd subsystem failed");
172
245
173 atexit(cleanup);
246 /* Queue ATIOs and INOTs on descriptor */
247 if (init_ccbs() != 0)
248 errx(1, "init_ccbs failed");
174
249
175 pump_events();
250 if (debug)
251 warnx("main loop beginning");
252 request_loop();
176
253
177 return (0);
254 exit(0);
178}
179
180static void
181cleanup()
182{
255}
256
257static void
258cleanup()
259{
260 struct ccb_hdr *ccb_h;
261
183 if (debug) {
262 if (debug) {
263 warnx("cleanup called");
184 debug = 0;
264 debug = 0;
185 (void) ioctl(targfd, TARGIODEBUG, &debug);
265 ioctl(targ_fd, TARGIOCDEBUG, &debug);
186 }
266 }
187 close(targfd);
188 if (ioctl(targctlfd, TARGCTLIOFREEUNIT, &alloc_unit) == -1) {
189 perror("TARGCTLIOFREEUNIT");
267 ioctl(targ_fd, TARGIOCDISABLE, NULL);
268 close(targ_fd);
269
270 while ((ccb_h = TAILQ_FIRST(&pending_queue)) != NULL) {
271 TAILQ_REMOVE(&pending_queue, ccb_h, periph_links.tqe);
272 free_ccb((union ccb *)ccb_h);
190 }
273 }
191 close(targctlfd);
274 while ((ccb_h = TAILQ_FIRST(&work_queue)) != NULL) {
275 TAILQ_REMOVE(&work_queue, ccb_h, periph_links.tqe);
276 free_ccb((union ccb *)ccb_h);
277 }
278
279 if (kq_fd != -1)
280 close(kq_fd);
192}
193
281}
282
194static void
195pump_events()
283/* Allocate ATIOs/INOTs and queue on HBA */
284static int
285init_ccbs()
196{
286{
197 struct pollfd targpoll;
287 int i;
198
288
199 targpoll.fd = targfd;
200 targpoll.events = POLLRDNORM|POLLWRNORM;
289 for (i = 0; i < MAX_INITIATORS; i++) {
290 struct ccb_accept_tio *atio;
291 struct atio_descr *a_descr;
292 struct ccb_immed_notify *inot;
201
293
202 while (quit == 0) {
203 int retval;
204
205 retval = poll(&targpoll, 1, INFTIM);
206
207 if (retval == -1) {
208 if (errno == EINTR)
209 continue;
210 perror("Poll Failed");
211 exit(EX_SOFTWARE);
294 atio = (struct ccb_accept_tio *)malloc(sizeof(*atio));
295 if (atio == NULL) {
296 warn("malloc ATIO");
297 return (-1);
212 }
298 }
213
214 if (retval == 0) {
215 perror("Poll returned 0 although timeout infinite???");
216 exit(EX_SOFTWARE);
299 a_descr = (struct atio_descr *)malloc(sizeof(*a_descr));
300 if (a_descr == NULL) {
301 free(atio);
302 warn("malloc atio_descr");
303 return (-1);
217 }
304 }
305 atio->ccb_h.func_code = XPT_ACCEPT_TARGET_IO;
306 atio->ccb_h.targ_descr = a_descr;
307 send_ccb((union ccb *)atio, /*priority*/1);
218
308
219 if (retval > 1) {
220 perror("Poll returned more fds ready than allocated");
221 exit(EX_SOFTWARE);
309 inot = (struct ccb_immed_notify *)malloc(sizeof(*inot));
310 if (inot == NULL) {
311 warn("malloc INOT");
312 return (-1);
222 }
313 }
314 inot->ccb_h.func_code = XPT_IMMED_NOTIFY;
315 send_ccb((union ccb *)inot, /*priority*/1);
316 }
223
317
224 /* Process events */
225 if ((targpoll.revents & POLLERR) != 0) {
226 handle_exception();
227 }
318 return (0);
319}
228
320
229 if ((targpoll.revents & POLLRDNORM) != 0) {
230 retval = read(targfd, buf, bufsize);
321static void
322request_loop()
323{
324 struct kevent events[MAX_EVENTS];
325 struct timespec ts, *tptr;
326 int quit;
231
327
232 if (retval == -1) {
233 perror("Read from targ failed");
234 /* Go look for exceptions */
328 /* Register kqueue for event notification */
329 if ((kq_fd = kqueue()) < 0)
330 err(1, "init kqueue");
331
332 /* Set up some default events */
333 EV_SET(&events[0], SIGHUP, EVFILT_SIGNAL, EV_ADD|EV_ENABLE, 0, 0, 0);
334 EV_SET(&events[1], SIGINT, EVFILT_SIGNAL, EV_ADD|EV_ENABLE, 0, 0, 0);
335 EV_SET(&events[2], SIGTERM, EVFILT_SIGNAL, EV_ADD|EV_ENABLE, 0, 0, 0);
336 EV_SET(&events[3], targ_fd, EVFILT_READ, EV_ADD|EV_ENABLE, 0, 0, 0);
337 if (kevent(kq_fd, events, 4, NULL, 0, NULL) < 0)
338 err(1, "kevent signal registration");
339
340 ts.tv_sec = 0;
341 ts.tv_nsec = 0;
342 tptr = NULL;
343 quit = 0;
344
345 /* Loop until user signal */
346 while (quit == 0) {
347 int retval, i;
348 struct ccb_hdr *ccb_h;
349
350 /* Check for the next signal, read ready, or AIO completion */
351 retval = kevent(kq_fd, NULL, 0, events, MAX_EVENTS, tptr);
352 if (retval < 0) {
353 if (errno == EINTR) {
354 if (debug)
355 warnx("EINTR, looping");
235 continue;
356 continue;
236 } else {
237 retval = write(ofd, buf, retval);
238 if (retval == -1) {
239 perror("Write to file failed");
240 }
357 }
358 else {
359 err(1, "kevent failed");
241 }
360 }
361 } else if (retval > MAX_EVENTS) {
362 errx(1, "kevent returned more events than allocated?");
242 }
243
363 }
364
244 if ((targpoll.revents & POLLWRNORM) != 0) {
245 int amount_read;
365 /* Process all received events. */
366 for (i = 0; i < retval; i++) {
367 if ((events[i].flags & EV_ERROR) != 0)
368 errx(1, "kevent registration failed");
246
369
247 retval = read(ifd, buf, bufsize);
248 if (retval == -1) {
249 perror("Read from file failed");
250 exit(EX_SOFTWARE);
370 switch (events[i].filter) {
371 case EVFILT_READ:
372 if (debug)
373 warnx("read ready");
374 handle_read();
375 break;
376 case EVFILT_AIO:
377 {
378 struct ccb_scsiio *ctio;
379 struct ctio_descr *c_descr;
380 if (debug)
381 warnx("aio ready");
382
383 ctio = (struct ccb_scsiio *)events[i].udata;
384 c_descr = (struct ctio_descr *)
385 ctio->ccb_h.targ_descr;
386 c_descr->event = AIO_DONE;
387 /* Queue on the appropriate ATIO */
388 queue_io(ctio);
389 /* Process any queued completions. */
390 run_queue(c_descr->atio);
391 break;
251 }
392 }
393 case EVFILT_SIGNAL:
394 if (debug)
395 warnx("signal ready, setting quit");
396 quit = 1;
397 break;
398 default:
399 warnx("unknown event %#x", events[i].filter);
400 break;
401 }
252
402
253 amount_read = retval;
254 retval = write(targfd, buf, retval);
255 if (retval == -1) {
256 perror("Write to targ failed");
257 retval = 0;
403 if (debug)
404 warnx("event done");
405 }
406
407 /* Grab the first CCB and perform one work unit. */
408 if ((ccb_h = TAILQ_FIRST(&work_queue)) != NULL) {
409 union ccb *ccb;
410
411 ccb = (union ccb *)ccb_h;
412 switch (ccb_h->func_code) {
413 case XPT_ACCEPT_TARGET_IO:
414 /* Start one more transfer. */
415 retval = work_atio(&ccb->atio);
416 break;
417 case XPT_IMMED_NOTIFY:
418 retval = work_inot(&ccb->cin);
419 break;
420 default:
421 warnx("Unhandled ccb type %#x on workq",
422 ccb_h->func_code);
423 abort();
424 /* NOTREACHED */
258 }
259
425 }
426
260 /* Backup in our input stream on short writes */
261 if (retval != amount_read)
262 lseek(ifd, retval - amount_read, SEEK_CUR);
427 /* Assume work function handled the exception */
428 if ((ccb_h->status & CAM_DEV_QFRZN) != 0) {
429 warnx("Queue frozen receiving CCB, releasing");
430 rel_simq();
431 }
432
433 /* No more work needed for this command. */
434 if (retval == 0) {
435 TAILQ_REMOVE(&work_queue, ccb_h,
436 periph_links.tqe);
437 }
263 }
438 }
439
440 /*
441 * Poll for new events (i.e. completions) while we
442 * are processing CCBs on the work_queue. Once it's
443 * empty, use an infinite wait.
444 */
445 if (!TAILQ_EMPTY(&work_queue))
446 tptr = &ts;
447 else
448 tptr = NULL;
264 }
265}
266
449 }
450}
451
452/* CCBs are ready from the kernel */
267static void
453static void
268handle_exception()
454handle_read()
269{
455{
270 targ_exception exceptions;
456 union ccb *ccb_array[MAX_INITIATORS], *ccb;
457 int ccb_count, i;
271
458
272 if (ioctl(targfd, TARGIOCFETCHEXCEPTION, &exceptions) == -1) {
273 perror("TARGIOCFETCHEXCEPTION");
274 exit(EX_SOFTWARE);
459 ccb_count = read(targ_fd, ccb_array, sizeof(ccb_array));
460 if (ccb_count <= 0) {
461 warn("read ccb ptrs");
462 return;
275 }
463 }
464 ccb_count /= sizeof(union ccb *);
465 if (ccb_count < 1) {
466 warnx("truncated read ccb ptr?");
467 return;
468 }
276
469
277 printf("Saw exceptions %x\n", exceptions);
278 if ((exceptions & TARG_EXCEPT_DEVICE_INVALID) != 0) {
279 /* Device went away. Nothing more to do. */
280 printf("Device went away\n");
281 exit(0);
470 for (i = 0; i < ccb_count; i++) {
471 ccb = ccb_array[i];
472 TAILQ_REMOVE(&pending_queue, &ccb->ccb_h, periph_links.tqe);
473
474 switch (ccb->ccb_h.func_code) {
475 case XPT_ACCEPT_TARGET_IO:
476 {
477 struct ccb_accept_tio *atio;
478 struct atio_descr *a_descr;
479
480 /* Initialize ATIO descr for this transaction */
481 atio = &ccb->atio;
482 a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
483 bzero(a_descr, sizeof(*a_descr));
484 TAILQ_INIT(&a_descr->cmplt_io);
485 a_descr->flags = atio->ccb_h.flags &
486 (CAM_DIS_DISCONNECT | CAM_TAG_ACTION_VALID);
487 /* XXX add a_descr->priority */
488 if ((atio->ccb_h.flags & CAM_CDB_POINTER) == 0)
489 a_descr->cdb = atio->cdb_io.cdb_bytes;
490 else
491 a_descr->cdb = atio->cdb_io.cdb_ptr;
492
493 /* ATIOs are processed in FIFO order */
494 TAILQ_INSERT_TAIL(&work_queue, &ccb->ccb_h,
495 periph_links.tqe);
496 break;
497 }
498 case XPT_CONT_TARGET_IO:
499 {
500 struct ccb_scsiio *ctio;
501 struct ctio_descr *c_descr;
502
503 ctio = &ccb->ctio;
504 c_descr = (struct ctio_descr *)ctio->ccb_h.targ_descr;
505 c_descr->event = CTIO_DONE;
506 /* Queue on the appropriate ATIO */
507 queue_io(ctio);
508 /* Process any queued completions. */
509 run_queue(c_descr->atio);
510 break;
511 }
512 case XPT_IMMED_NOTIFY:
513 /* INOTs are handled with priority */
514 TAILQ_INSERT_HEAD(&work_queue, &ccb->ccb_h,
515 periph_links.tqe);
516 break;
517 default:
518 warnx("Unhandled ccb type %#x in handle_read",
519 ccb->ccb_h.func_code);
520 break;
521 }
282 }
522 }
523}
283
524
284 if ((exceptions & TARG_EXCEPT_UNKNOWN_ATIO) != 0) {
285 struct ccb_accept_tio atio;
286 struct ioc_initiator_state ioc_istate;
525/* Process an ATIO CCB from the kernel */
526int
527work_atio(struct ccb_accept_tio *atio)
528{
529 struct ccb_scsiio *ctio;
530 struct atio_descr *a_descr;
531 struct ctio_descr *c_descr;
532 cam_status status;
533 int ret;
534
535 if (debug)
536 warnx("Working on ATIO %p", atio);
537
538 a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
539
540 /* Get a CTIO and initialize it according to our known parameters */
541 ctio = get_ctio();
542 if (ctio == NULL)
543 return (1);
544 ret = 0;
545 ctio->ccb_h.flags = a_descr->flags;
546 ctio->tag_id = atio->tag_id;
547 ctio->init_id = atio->init_id;
548 /* XXX priority needs to be added to a_descr */
549 c_descr = (struct ctio_descr *)ctio->ccb_h.targ_descr;
550 c_descr->atio = atio;
551 if ((a_descr->flags & CAM_DIR_IN) != 0)
552 c_descr->offset = a_descr->base_off + a_descr->targ_req;
553 else if ((a_descr->flags & CAM_DIR_MASK) == CAM_DIR_OUT)
554 c_descr->offset = a_descr->base_off + a_descr->init_req;
555
556 /*
557 * Return a check condition if there was an error while
558 * receiving this ATIO.
559 */
560 if (atio->sense_len != 0) {
287 struct scsi_sense_data *sense;
561 struct scsi_sense_data *sense;
288 union ccb ccb;
289
562
290 if (ioctl(targfd, TARGIOCFETCHATIO, &atio) == -1) {
291 perror("TARGIOCFETCHATIO");
292 exit(EX_SOFTWARE);
563 if (debug) {
564 warnx("ATIO with %u bytes sense received",
565 atio->sense_len);
293 }
566 }
567 sense = &atio->sense_data;
568 tcmd_sense(ctio->init_id, ctio, sense->flags,
569 sense->add_sense_code, sense->add_sense_code_qual);
570 send_ccb((union ccb *)ctio, /*priority*/1);
571 return (0);
572 }
294
573
295 printf("Ignoring unhandled command 0x%x for Id %d\n",
296 atio.cdb_io.cdb_bytes[0], atio.init_id);
574 status = atio->ccb_h.status & CAM_STATUS_MASK;
575 switch (status) {
576 case CAM_CDB_RECVD:
577 ret = tcmd_handle(atio, ctio, ATIO_WORK);
578 break;
579 case CAM_REQ_ABORTED:
580 /* Requeue on HBA */
581 TAILQ_REMOVE(&work_queue, &atio->ccb_h, periph_links.tqe);
582 send_ccb((union ccb *)atio, /*priority*/1);
583 ret = 1;
584 break;
585 default:
586 warnx("ATIO completed with unhandled status %#x", status);
587 abort();
588 /* NOTREACHED */
589 break;
590 }
297
591
298 ioc_istate.initiator_id = atio.init_id;
299 if (ioctl(targfd, TARGIOCGETISTATE, &ioc_istate) == -1) {
300 perror("TARGIOCGETISTATE");
301 exit(EX_SOFTWARE);
302 }
592 return (ret);
593}
303
594
304 /* Send back Illegal Command code status */
305 ioc_istate.istate.pending_ca |= CA_CMD_SENSE;
306 sense = &ioc_istate.istate.sense_data;
307 bzero(sense, sizeof(*sense));
308 sense->error_code = SSD_CURRENT_ERROR;
309 sense->flags = SSD_KEY_ILLEGAL_REQUEST;
310 sense->add_sense_code = 0x20;
311 sense->add_sense_code_qual = 0x00;
312 sense->extra_len = offsetof(struct scsi_sense_data, fru)
313 - offsetof(struct scsi_sense_data, extra_len);
595static void
596queue_io(struct ccb_scsiio *ctio)
597{
598 struct ccb_hdr *ccb_h;
599 struct io_queue *ioq;
600 struct ctio_descr *c_descr, *curr_descr;
601
602 c_descr = (struct ctio_descr *)ctio->ccb_h.targ_descr;
603 /* If the completion is for a specific ATIO, queue in order */
604 if (c_descr->atio != NULL) {
605 struct atio_descr *a_descr;
314
606
315 if (ioctl(targfd, TARGIOCSETISTATE, &ioc_istate) == -1) {
316 perror("TARGIOCSETISTATE");
317 exit(EX_SOFTWARE);
607 a_descr = (struct atio_descr *)c_descr->atio->ccb_h.targ_descr;
608 ioq = &a_descr->cmplt_io;
609 } else {
610 errx(1, "CTIO %p has NULL ATIO", ctio);
611 }
612
613 /* Insert in order, sorted by offset */
614 if (!TAILQ_EMPTY(ioq)) {
615 TAILQ_FOREACH_REVERSE(ccb_h, ioq, io_queue, periph_links.tqe) {
616 curr_descr = (struct ctio_descr *)ccb_h->targ_descr;
617 if (curr_descr->offset <= c_descr->offset) {
618 TAILQ_INSERT_AFTER(ioq, ccb_h, &ctio->ccb_h,
619 periph_links.tqe);
620 break;
621 }
622 if (TAILQ_PREV(ccb_h, io_queue, periph_links.tqe)
623 == NULL) {
624 TAILQ_INSERT_BEFORE(ccb_h, &ctio->ccb_h,
625 periph_links.tqe);
626 break;
627 }
318 }
628 }
629 } else {
630 TAILQ_INSERT_HEAD(ioq, &ctio->ccb_h, periph_links.tqe);
631 }
632}
319
633
320 /* Clear the exception so the kernel will take our response */
321 if (ioctl(targfd, TARGIOCCLEAREXCEPTION, &exceptions) == -1) {
322 perror("TARGIOCCLEAREXCEPTION");
323 exit(EX_SOFTWARE);
634/*
635 * Go through all completed AIO/CTIOs for a given ATIO and advance data
636 * counts, start continuation IO, etc.
637 */
638static void
639run_queue(struct ccb_accept_tio *atio)
640{
641 struct atio_descr *a_descr;
642 struct ccb_hdr *ccb_h;
643 int sent_status, event;
644
645 if (atio == NULL)
646 return;
647
648 a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
649
650 while ((ccb_h = TAILQ_FIRST(&a_descr->cmplt_io)) != NULL) {
651 struct ccb_scsiio *ctio;
652 struct ctio_descr *c_descr;
653
654 ctio = (struct ccb_scsiio *)ccb_h;
655 c_descr = (struct ctio_descr *)ctio->ccb_h.targ_descr;
656
657 /* If completed item is in range, call handler */
658 if ((c_descr->event == AIO_DONE &&
659 c_descr->offset == a_descr->base_off + a_descr->targ_ack)
660 || (c_descr->event == CTIO_DONE &&
661 c_descr->offset == a_descr->base_off + a_descr->init_ack)) {
662 sent_status = (ccb_h->flags & CAM_SEND_STATUS) != 0;
663 event = c_descr->event;
664
665 TAILQ_REMOVE(&a_descr->cmplt_io, ccb_h,
666 periph_links.tqe);
667 tcmd_handle(atio, ctio, c_descr->event);
668
669 /* If entire transfer complete, send back ATIO */
670 if (sent_status != 0 && event == CTIO_DONE)
671 send_ccb((union ccb *)atio, /*priority*/1);
672 } else {
673 /* Gap in offsets so wait until later callback */
674 if (debug)
675 warnx("IO %p out of order", ccb_h);
676 break;
324 }
677 }
678 }
679}
325
680
326 bzero(&ccb, sizeof(ccb));
327 cam_fill_ctio(&ccb.csio,
328 /*retries*/2,
329 /*cbfcnp*/NULL,
330 CAM_DIR_NONE | CAM_SEND_STATUS,
331 (atio.ccb_h.flags & CAM_TAG_ACTION_VALID)?
332 MSG_SIMPLE_Q_TAG : 0,
333 atio.tag_id,
334 atio.init_id,
335 SCSI_STATUS_CHECK_COND,
336 /*data_ptr*/NULL,
337 /*dxfer_len*/0,
338 /*timeout*/5 * 1000);
339 /*
340 * Make sure that periph_priv pointers are clean.
341 */
342 bzero(&ccb.ccb_h.periph_priv, sizeof ccb.ccb_h.periph_priv);
681static int
682work_inot(struct ccb_immed_notify *inot)
683{
684 cam_status status;
685 int sense;
343
686
344 if (ioctl(targfd, TARGIOCCOMMAND, &ccb) == -1) {
345 perror("TARGIOCCOMMAND");
346 exit(EX_SOFTWARE);
687 if (debug)
688 warnx("Working on INOT %p", inot);
689
690 status = inot->ccb_h.status;
691 sense = (status & CAM_AUTOSNS_VALID) != 0;
692 status &= CAM_STATUS_MASK;
693
694 switch (status) {
695 case CAM_SCSI_BUS_RESET:
696 tcmd_ua(CAM_TARGET_WILDCARD, UA_BUS_RESET);
697 abort_all_pending();
698 break;
699 case CAM_BDR_SENT:
700 tcmd_ua(CAM_TARGET_WILDCARD, UA_BDR);
701 abort_all_pending();
702 break;
703 case CAM_MESSAGE_RECV:
704 switch (inot->message_args[0]) {
705 case MSG_TASK_COMPLETE:
706 case MSG_INITIATOR_DET_ERR:
707 case MSG_ABORT_TASK_SET:
708 case MSG_MESSAGE_REJECT:
709 case MSG_NOOP:
710 case MSG_PARITY_ERROR:
711 case MSG_TARGET_RESET:
712 case MSG_ABORT_TASK:
713 case MSG_CLEAR_TASK_SET:
714 default:
715 warnx("INOT message %#x", inot->message_args[0]);
716 break;
347 }
717 }
348
349 } else {
350 if (ioctl(targfd, TARGIOCCLEAREXCEPTION, &exceptions) == -1) {
351 perror("TARGIOCCLEAREXCEPTION");
352 exit(EX_SOFTWARE);
353 }
718 break;
719 case CAM_REQ_ABORTED:
720 warnx("INOT %p aborted", inot);
721 break;
722 default:
723 warnx("Unhandled INOT status %#x", status);
724 break;
354 }
355
725 }
726
727 /* If there is sense data, use it */
728 if (sense != 0) {
729 struct scsi_sense_data *sense;
730
731 sense = &inot->sense_data;
732 tcmd_sense(inot->initiator_id, NULL, sense->flags,
733 sense->add_sense_code, sense->add_sense_code_qual);
734 if (debug)
735 warnx("INOT has sense: %#x", sense->flags);
736 }
737
738 /* Requeue on SIM */
739 TAILQ_REMOVE(&work_queue, &inot->ccb_h, periph_links.tqe);
740 send_ccb((union ccb *)inot, /*priority*/1);
741
742 return (1);
356}
357
743}
744
745void
746send_ccb(union ccb *ccb, int priority)
747{
748 if (debug)
749 warnx("sending ccb (%#x)", ccb->ccb_h.func_code);
750 ccb->ccb_h.pinfo.priority = priority;
751 if (XPT_FC_IS_QUEUED(ccb)) {
752 TAILQ_INSERT_TAIL(&pending_queue, &ccb->ccb_h,
753 periph_links.tqe);
754 }
755 if (write(targ_fd, &ccb, sizeof(ccb)) != sizeof(ccb)) {
756 warn("write ccb");
757 ccb->ccb_h.status = CAM_PROVIDE_FAIL;
758 }
759}
760
761/* Return a CTIO/descr/buf combo from the freelist or malloc one */
762static struct ccb_scsiio *
763get_ctio()
764{
765 struct ccb_scsiio *ctio;
766 struct ctio_descr *c_descr;
767 struct sigevent *se;
768
769 if (num_ctios == MAX_CTIOS)
770 return (NULL);
771
772 ctio = (struct ccb_scsiio *)malloc(sizeof(*ctio));
773 if (ctio == NULL) {
774 warn("malloc CTIO");
775 return (NULL);
776 }
777 c_descr = (struct ctio_descr *)malloc(sizeof(*c_descr));
778 if (c_descr == NULL) {
779 free(ctio);
780 warn("malloc ctio_descr");
781 return (NULL);
782 }
783 c_descr->buf = malloc(buf_size);
784 if (c_descr->buf == NULL) {
785 free(c_descr);
786 free(ctio);
787 warn("malloc backing store");
788 return (NULL);
789 }
790 num_ctios++;
791
792 /* Initialize CTIO, CTIO descr, and AIO */
793 ctio->ccb_h.func_code = XPT_CONT_TARGET_IO;
794 ctio->ccb_h.retry_count = 2;
795 ctio->ccb_h.timeout = 5;
796 ctio->data_ptr = c_descr->buf;
797 ctio->ccb_h.targ_descr = c_descr;
798 c_descr->aiocb.aio_buf = c_descr->buf;
799 c_descr->aiocb.aio_fildes = file_fd;
800 se = &c_descr->aiocb.aio_sigevent;
801 se->sigev_notify = SIGEV_KEVENT;
802 se->sigev_notify_kqueue = kq_fd;
803 se->sigev_value.sigval_ptr = ctio;
804
805 return (ctio);
806}
807
808void
809free_ccb(union ccb *ccb)
810{
811 switch (ccb->ccb_h.func_code) {
812 case XPT_CONT_TARGET_IO:
813 {
814 struct ctio_descr *c_descr;
815
816 c_descr = (struct ctio_descr *)ccb->ccb_h.targ_descr;
817 free(c_descr->buf);
818 num_ctios--;
819 /* FALLTHROUGH */
820 }
821 case XPT_ACCEPT_TARGET_IO:
822 free(ccb->ccb_h.targ_descr);
823 /* FALLTHROUGH */
824 case XPT_IMMED_NOTIFY:
825 default:
826 free(ccb);
827 break;
828 }
829}
830
831static cam_status
832get_sim_flags(u_int16_t *flags)
833{
834 struct ccb_pathinq cpi;
835 cam_status status;
836
837 /* Find SIM capabilities */
838 bzero(&cpi, sizeof(cpi));
839 cpi.ccb_h.func_code = XPT_PATH_INQ;
840 send_ccb((union ccb *)&cpi, /*priority*/1);
841 status = cpi.ccb_h.status & CAM_STATUS_MASK;
842 if (status != CAM_REQ_CMP) {
843 fprintf(stderr, "CPI failed, status %#x\n", status);
844 return (status);
845 }
846
847 /* Can only enable on controllers that support target mode */
848 if ((cpi.target_sprt & PIT_PROCESSOR) == 0) {
849 fprintf(stderr, "HBA does not support target mode\n");
850 status = CAM_PATH_INVALID;
851 return (status);
852 }
853
854 *flags = cpi.hba_inquiry;
855 return (status);
856}
857
358static void
858static void
359quit_handler(int signum)
859rel_simq()
360{
860{
361 quit = 1;
861 struct ccb_relsim crs;
862
863 bzero(&crs, sizeof(crs));
864 crs.ccb_h.func_code = XPT_REL_SIMQ;
865 crs.release_flags = RELSIM_RELEASE_AFTER_QEMPTY;
866 crs.openings = 0;
867 crs.release_timeout = 0;
868 crs.qfrozen_cnt = 0;
869 send_ccb((union ccb *)&crs, /*priority*/0);
362}
363
870}
871
872/* Cancel all pending CCBs. */
364static void
873static void
365usage()
874abort_all_pending()
366{
875{
876 struct ccb_abort cab;
877 struct ccb_hdr *ccb_h;
367
878
368 (void)fprintf(stderr,
369"usage: %-16s [ -d ] [-o output_file] [-i input_file] -p path -t target -l lun\n",
370 appname);
879 if (debug)
880 warnx("abort_all_pending");
371
881
372 exit(EX_USAGE);
882 bzero(&cab, sizeof(cab));
883 cab.ccb_h.func_code = XPT_ABORT;
884 TAILQ_FOREACH(ccb_h, &pending_queue, periph_links.tqe) {
885 if (debug)
886 warnx("Aborting pending CCB %p\n", ccb_h);
887 cab.abort_ccb = (union ccb *)ccb_h;
888 send_ccb((union ccb *)&cab, /*priority*/1);
889 if (cab.ccb_h.status != CAM_REQ_CMP) {
890 warnx("Unable to abort CCB, status %#x\n",
891 cab.ccb_h.status);
892 }
893 }
373}
374
894}
895
896static void
897usage()
898{
899 fprintf(stderr,
900 "Usage: scsi_target [-AdST] [-b bufsize] [-c sectorsize]\n"
901 "\t\t[-r numbufs] [-s volsize] [-W 8,16,32]\n"
902 "\t\tbus:target:lun filename\n");
903 exit(1);
904}