139215Sgibbs/* 2107178Snjl * SCSI Disk Emulator 339215Sgibbs * 4107178Snjl * Copyright (c) 2002 Nate Lawson. 539215Sgibbs * All rights reserved. 639215Sgibbs * 739215Sgibbs * Redistribution and use in source and binary forms, with or without 839215Sgibbs * modification, are permitted provided that the following conditions 939215Sgibbs * are met: 1039215Sgibbs * 1. Redistributions of source code must retain the above copyright 1139215Sgibbs * notice, this list of conditions, and the following disclaimer, 1239215Sgibbs * without modification, immediately at the beginning of the file. 1339215Sgibbs * 2. The name of the author may not be used to endorse or promote products 1439215Sgibbs * derived from this software without specific prior written permission. 1539215Sgibbs * 1639215Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1739215Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1839215Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1939215Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 2039215Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2139215Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2239215Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2339215Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2439215Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2539215Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2639215Sgibbs * SUCH DAMAGE. 2739215Sgibbs * 2850476Speter * $FreeBSD$ 2939215Sgibbs */ 3039215Sgibbs 3139215Sgibbs#include <sys/types.h> 32121184Ssimokawa#include <ctype.h> 3344498Sgibbs#include <errno.h> 34107178Snjl#include <err.h> 3539215Sgibbs#include <fcntl.h> 3644498Sgibbs#include <signal.h> 3739215Sgibbs#include <stddef.h> 3839215Sgibbs#include <stdio.h> 3939215Sgibbs#include <stdlib.h> 40107178Snjl#include <string.h> 4139215Sgibbs#include <sysexits.h> 4239215Sgibbs#include <unistd.h> 43107178Snjl#include <aio.h> 44109161Snjl#include <assert.h> 45107178Snjl#include <sys/stat.h> 46107178Snjl#include <sys/queue.h> 47107178Snjl#include <sys/event.h> 48107178Snjl#include <sys/param.h> 49120428Ssimokawa#include <sys/disk.h> 50107178Snjl#include <cam/cam_queue.h> 5139215Sgibbs#include <cam/scsi/scsi_all.h> 52107178Snjl#include <cam/scsi/scsi_targetio.h> 5339215Sgibbs#include <cam/scsi/scsi_message.h> 54107178Snjl#include "scsi_target.h" 5539215Sgibbs 56107178Snjl/* Maximum amount to transfer per CTIO */ 57107178Snjl#define MAX_XFER MAXPHYS 58107178Snjl/* Maximum number of allocated CTIOs */ 59162704Smjacob#define MAX_CTIOS 64 60107178Snjl/* Maximum sector size for emulated volume */ 61107178Snjl#define MAX_SECTOR 32768 62107178Snjl 63107178Snjl/* Global variables */ 64107178Snjlint debug; 65162704Smjacobint notaio = 0; 66121184Ssimokawaoff_t volume_size; 67121184Ssimokawau_int sector_size; 68107178Snjlsize_t buf_size; 69107178Snjl 70107178Snjl/* Local variables */ 71107178Snjlstatic int targ_fd; 72107178Snjlstatic int kq_fd; 73107178Snjlstatic int file_fd; 74107178Snjlstatic int num_ctios; 75107178Snjlstatic struct ccb_queue pending_queue; 76107178Snjlstatic struct ccb_queue work_queue; 77107178Snjlstatic struct ioc_enable_lun ioc_enlun = { 7844498Sgibbs CAM_BUS_WILDCARD, 7944498Sgibbs CAM_TARGET_WILDCARD, 8044498Sgibbs CAM_LUN_WILDCARD 8144498Sgibbs}; 8239215Sgibbs 83107178Snjl/* Local functions */ 84107178Snjlstatic void cleanup(void); 85107178Snjlstatic int init_ccbs(void); 86107178Snjlstatic void request_loop(void); 87107178Snjlstatic void handle_read(void); 88107178Snjl/* static int work_atio(struct ccb_accept_tio *); */ 89107178Snjlstatic void queue_io(struct ccb_scsiio *); 90162704Smjacobstatic int run_queue(struct ccb_accept_tio *); 91237825Skenstatic int work_inot(struct ccb_immediate_notify *); 92107178Snjlstatic struct ccb_scsiio * 93107178Snjl get_ctio(void); 94107178Snjl/* static void free_ccb(union ccb *); */ 95107178Snjlstatic cam_status get_sim_flags(u_int16_t *); 96107178Snjlstatic void rel_simq(void); 97107178Snjlstatic void abort_all_pending(void); 98107178Snjlstatic void usage(void); 9939215Sgibbs 10039215Sgibbsint 10139215Sgibbsmain(int argc, char *argv[]) 10239215Sgibbs{ 103107178Snjl int ch, unit; 104107178Snjl char *file_name, targname[16]; 105107178Snjl u_int16_t req_flags, sim_flags; 106107178Snjl off_t user_size; 10739215Sgibbs 108107178Snjl /* Initialize */ 109107178Snjl debug = 0; 110107178Snjl req_flags = sim_flags = 0; 111107178Snjl user_size = 0; 112107178Snjl targ_fd = file_fd = kq_fd = -1; 113107178Snjl num_ctios = 0; 114107178Snjl sector_size = SECTOR_SIZE; 115107178Snjl buf_size = DFLTPHYS; 116107178Snjl 117107178Snjl /* Prepare resource pools */ 118107178Snjl TAILQ_INIT(&pending_queue); 119107178Snjl TAILQ_INIT(&work_queue); 120107178Snjl 121162704Smjacob while ((ch = getopt(argc, argv, "AdSTYb:c:s:W:")) != -1) { 12239215Sgibbs switch(ch) { 123107178Snjl case 'A': 124107178Snjl req_flags |= SID_Addr16; 12539215Sgibbs break; 126107178Snjl case 'd': 127107178Snjl debug = 1; 12839215Sgibbs break; 129107178Snjl case 'S': 130107178Snjl req_flags |= SID_Sync; 13144498Sgibbs break; 132107178Snjl case 'T': 133107178Snjl req_flags |= SID_CmdQue; 13444498Sgibbs break; 135107178Snjl case 'b': 136107178Snjl buf_size = atoi(optarg); 137107178Snjl if (buf_size < 256 || buf_size > MAX_XFER) 138107178Snjl errx(1, "Unreasonable buf size: %s", optarg); 13944498Sgibbs break; 140107178Snjl case 'c': 141107178Snjl sector_size = atoi(optarg); 142107178Snjl if (sector_size < 512 || sector_size > MAX_SECTOR) 143107178Snjl errx(1, "Unreasonable sector size: %s", optarg); 14463185Smjacob break; 145107178Snjl case 's': 146121184Ssimokawa { 147121184Ssimokawa int last, shift = 0; 148121184Ssimokawa 149121184Ssimokawa last = strlen(optarg) - 1; 150121184Ssimokawa if (last > 0) { 151121184Ssimokawa switch (tolower(optarg[last])) { 152121184Ssimokawa case 'e': 153121184Ssimokawa shift += 10; 154121184Ssimokawa /* FALLTHROUGH */ 155121184Ssimokawa case 'p': 156121184Ssimokawa shift += 10; 157121184Ssimokawa /* FALLTHROUGH */ 158121184Ssimokawa case 't': 159121184Ssimokawa shift += 10; 160121184Ssimokawa /* FALLTHROUGH */ 161121184Ssimokawa case 'g': 162121184Ssimokawa shift += 10; 163121184Ssimokawa /* FALLTHROUGH */ 164121184Ssimokawa case 'm': 165121184Ssimokawa shift += 10; 166121184Ssimokawa /* FALLTHROUGH */ 167121184Ssimokawa case 'k': 168121184Ssimokawa shift += 10; 169121184Ssimokawa optarg[last] = 0; 170121184Ssimokawa break; 171121184Ssimokawa } 172121184Ssimokawa } 173107178Snjl user_size = strtoll(optarg, (char **)NULL, /*base*/10); 174121184Ssimokawa user_size <<= shift; 175107178Snjl if (user_size < 0) 176107178Snjl errx(1, "Unreasonable volume size: %s", optarg); 177107178Snjl break; 178121184Ssimokawa } 179107178Snjl case 'W': 180107178Snjl req_flags &= ~(SID_WBus16 | SID_WBus32); 181107178Snjl switch (atoi(optarg)) { 182107178Snjl case 8: 183107178Snjl /* Leave req_flags zeroed */ 184107178Snjl break; 185107178Snjl case 16: 186107178Snjl req_flags |= SID_WBus16; 187107178Snjl break; 188107178Snjl case 32: 189107178Snjl req_flags |= SID_WBus32; 190107178Snjl break; 191107178Snjl default: 192107178Snjl warnx("Width %s not supported", optarg); 193107178Snjl usage(); 194107178Snjl /* NOTREACHED */ 195107178Snjl } 196107178Snjl break; 197162704Smjacob case 'Y': 198162704Smjacob notaio = 1; 199162704Smjacob break; 20039215Sgibbs default: 20139215Sgibbs usage(); 20239215Sgibbs /* NOTREACHED */ 20339215Sgibbs } 20439215Sgibbs } 20539215Sgibbs argc -= optind; 20639215Sgibbs argv += optind; 207107178Snjl 208107178Snjl if (argc != 2) 20939215Sgibbs usage(); 21039215Sgibbs 211107178Snjl sscanf(argv[0], "%u:%u:%u", &ioc_enlun.path_id, &ioc_enlun.target_id, 212107178Snjl &ioc_enlun.lun_id); 213107178Snjl file_name = argv[1]; 214107178Snjl 215107178Snjl if (ioc_enlun.path_id == CAM_BUS_WILDCARD || 216107178Snjl ioc_enlun.target_id == CAM_TARGET_WILDCARD || 217107178Snjl ioc_enlun.lun_id == CAM_LUN_WILDCARD) { 218107178Snjl warnx("Incomplete target path specified"); 21944498Sgibbs usage(); 22044498Sgibbs /* NOTREACHED */ 22144498Sgibbs } 222107178Snjl /* We don't support any vendor-specific commands */ 223107178Snjl ioc_enlun.grp6_len = 0; 224107178Snjl ioc_enlun.grp7_len = 0; 22544498Sgibbs 226107178Snjl /* Open backing store for IO */ 227107178Snjl file_fd = open(file_name, O_RDWR); 228107178Snjl if (file_fd < 0) 229196955Ssbruno errx(EX_NOINPUT, "open backing store file"); 23044498Sgibbs 231107178Snjl /* Check backing store size or use the size user gave us */ 232107178Snjl if (user_size == 0) { 233107178Snjl struct stat st; 234107178Snjl 235107178Snjl if (fstat(file_fd, &st) < 0) 236107178Snjl err(1, "fstat file"); 237120428Ssimokawa#if __FreeBSD_version >= 500000 238120428Ssimokawa if ((st.st_mode & S_IFCHR) != 0) { 239120428Ssimokawa /* raw device */ 240120428Ssimokawa off_t mediasize; 241120428Ssimokawa if (ioctl(file_fd, DIOCGMEDIASIZE, &mediasize) < 0) 242120428Ssimokawa err(1, "DIOCGMEDIASIZE"); 243120428Ssimokawa 244120428Ssimokawa /* XXX get sector size by ioctl()?? */ 245120428Ssimokawa volume_size = mediasize / sector_size; 246120428Ssimokawa } else 247120428Ssimokawa#endif 248120428Ssimokawa volume_size = st.st_size / sector_size; 249107178Snjl } else { 250107178Snjl volume_size = user_size / sector_size; 25144498Sgibbs } 252121184Ssimokawa if (debug) 253162704Smjacob warnx("volume_size: %d bytes x " OFF_FMT " sectors", 254121184Ssimokawa sector_size, volume_size); 255121184Ssimokawa 256107178Snjl if (volume_size <= 0) 257107178Snjl errx(1, "volume must be larger than %d", sector_size); 25844498Sgibbs 259162704Smjacob if (notaio == 0) { 260109161Snjl struct aiocb aio, *aiop; 261109161Snjl 262162704Smjacob /* See if we have we have working AIO support */ 263109161Snjl memset(&aio, 0, sizeof(aio)); 264109161Snjl aio.aio_buf = malloc(sector_size); 265109161Snjl if (aio.aio_buf == NULL) 266109161Snjl err(1, "malloc"); 267109161Snjl aio.aio_fildes = file_fd; 268109161Snjl aio.aio_offset = 0; 269109161Snjl aio.aio_nbytes = sector_size; 270109161Snjl signal(SIGSYS, SIG_IGN); 271109161Snjl if (aio_read(&aio) != 0) { 272162704Smjacob printf("AIO support is not available- switchin to" 273162704Smjacob " single-threaded mode.\n"); 274162704Smjacob notaio = 1; 275162704Smjacob } else { 276162704Smjacob if (aio_waitcomplete(&aiop, NULL) != sector_size) 277162704Smjacob err(1, "aio_waitcomplete"); 278162704Smjacob assert(aiop == &aio); 279162704Smjacob signal(SIGSYS, SIG_DFL); 280109161Snjl } 281109161Snjl free((void *)aio.aio_buf); 282162704Smjacob if (debug && notaio == 0) 283109161Snjl warnx("aio support tested ok"); 284109161Snjl } 285109161Snjl 286107178Snjl /* Go through all the control devices and find one that isn't busy. */ 287107178Snjl unit = 0; 288107178Snjl do { 289107178Snjl snprintf(targname, sizeof(targname), "/dev/targ%d", unit++); 290107178Snjl targ_fd = open(targname, O_RDWR); 291107178Snjl } while (targ_fd < 0 && errno == EBUSY); 29244498Sgibbs 293107178Snjl if (targ_fd < 0) 294196955Ssbruno errx(1, "Tried to open %d devices, none available", unit); 295196955Ssbruno else 296197333Smjacob warnx("opened %s", targname); 29763185Smjacob 298107178Snjl /* The first three are handled by kevent() later */ 299107178Snjl signal(SIGHUP, SIG_IGN); 300107178Snjl signal(SIGINT, SIG_IGN); 301107178Snjl signal(SIGTERM, SIG_IGN); 302107178Snjl signal(SIGPROF, SIG_IGN); 303107178Snjl signal(SIGALRM, SIG_IGN); 304107178Snjl signal(SIGSTOP, SIG_IGN); 305107178Snjl signal(SIGTSTP, SIG_IGN); 30639215Sgibbs 307107178Snjl /* Register a cleanup handler to run when exiting */ 308107178Snjl atexit(cleanup); 309107178Snjl 310107178Snjl /* Enable listening on the specified LUN */ 311107178Snjl if (ioctl(targ_fd, TARGIOCENABLE, &ioc_enlun) != 0) 312107178Snjl err(1, "TARGIOCENABLE"); 313107178Snjl 314107178Snjl /* Enable debugging if requested */ 315107178Snjl if (debug) { 316107178Snjl if (ioctl(targ_fd, TARGIOCDEBUG, &debug) != 0) 317162704Smjacob warnx("TARGIOCDEBUG"); 31839215Sgibbs } 31939215Sgibbs 320107178Snjl /* Set up inquiry data according to what SIM supports */ 321107178Snjl if (get_sim_flags(&sim_flags) != CAM_REQ_CMP) 322107178Snjl errx(1, "get_sim_flags"); 323196955Ssbruno 324107178Snjl if (tcmd_init(req_flags, sim_flags) != 0) 325107178Snjl errx(1, "Initializing tcmd subsystem failed"); 32644498Sgibbs 327107178Snjl /* Queue ATIOs and INOTs on descriptor */ 328107178Snjl if (init_ccbs() != 0) 329107178Snjl errx(1, "init_ccbs failed"); 33049935Sgibbs 331107178Snjl if (debug) 332107178Snjl warnx("main loop beginning"); 333196955Ssbruno 334107178Snjl request_loop(); 33539215Sgibbs 336107178Snjl exit(0); 33749935Sgibbs} 33849935Sgibbs 33949935Sgibbsstatic void 34049935Sgibbscleanup() 34149935Sgibbs{ 342107178Snjl struct ccb_hdr *ccb_h; 343107178Snjl 34463290Smjacob if (debug) { 345107178Snjl warnx("cleanup called"); 34663290Smjacob debug = 0; 347107178Snjl ioctl(targ_fd, TARGIOCDEBUG, &debug); 34863290Smjacob } 349107178Snjl ioctl(targ_fd, TARGIOCDISABLE, NULL); 350107178Snjl close(targ_fd); 351107178Snjl 352107178Snjl while ((ccb_h = TAILQ_FIRST(&pending_queue)) != NULL) { 353107178Snjl TAILQ_REMOVE(&pending_queue, ccb_h, periph_links.tqe); 354107178Snjl free_ccb((union ccb *)ccb_h); 35544498Sgibbs } 356107178Snjl while ((ccb_h = TAILQ_FIRST(&work_queue)) != NULL) { 357107178Snjl TAILQ_REMOVE(&work_queue, ccb_h, periph_links.tqe); 358107178Snjl free_ccb((union ccb *)ccb_h); 359107178Snjl } 360107178Snjl 361107178Snjl if (kq_fd != -1) 362107178Snjl close(kq_fd); 36339215Sgibbs} 36439215Sgibbs 365107178Snjl/* Allocate ATIOs/INOTs and queue on HBA */ 366107178Snjlstatic int 367107178Snjlinit_ccbs() 368107178Snjl{ 369107178Snjl int i; 370107178Snjl 371107178Snjl for (i = 0; i < MAX_INITIATORS; i++) { 372107178Snjl struct ccb_accept_tio *atio; 373107178Snjl struct atio_descr *a_descr; 374255562Smav struct ccb_immediate_notify *inot; 375107178Snjl 376107178Snjl atio = (struct ccb_accept_tio *)malloc(sizeof(*atio)); 377107178Snjl if (atio == NULL) { 378107178Snjl warn("malloc ATIO"); 379107178Snjl return (-1); 380107178Snjl } 381107178Snjl a_descr = (struct atio_descr *)malloc(sizeof(*a_descr)); 382107178Snjl if (a_descr == NULL) { 383107178Snjl free(atio); 384107178Snjl warn("malloc atio_descr"); 385107178Snjl return (-1); 386107178Snjl } 387107178Snjl atio->ccb_h.func_code = XPT_ACCEPT_TARGET_IO; 388107178Snjl atio->ccb_h.targ_descr = a_descr; 389107178Snjl send_ccb((union ccb *)atio, /*priority*/1); 390107178Snjl 391255562Smav inot = (struct ccb_immediate_notify *)malloc(sizeof(*inot)); 392107178Snjl if (inot == NULL) { 393107178Snjl warn("malloc INOT"); 394107178Snjl return (-1); 395107178Snjl } 396237825Sken inot->ccb_h.func_code = XPT_IMMEDIATE_NOTIFY; 397107178Snjl send_ccb((union ccb *)inot, /*priority*/1); 398107178Snjl } 399107178Snjl 400107178Snjl return (0); 401107178Snjl} 402107178Snjl 40339215Sgibbsstatic void 404107178Snjlrequest_loop() 40539215Sgibbs{ 406107178Snjl struct kevent events[MAX_EVENTS]; 407107178Snjl struct timespec ts, *tptr; 408107178Snjl int quit; 40939215Sgibbs 410107178Snjl /* Register kqueue for event notification */ 411107178Snjl if ((kq_fd = kqueue()) < 0) 412107178Snjl err(1, "init kqueue"); 41339215Sgibbs 414107178Snjl /* Set up some default events */ 415107178Snjl EV_SET(&events[0], SIGHUP, EVFILT_SIGNAL, EV_ADD|EV_ENABLE, 0, 0, 0); 416107178Snjl EV_SET(&events[1], SIGINT, EVFILT_SIGNAL, EV_ADD|EV_ENABLE, 0, 0, 0); 417107178Snjl EV_SET(&events[2], SIGTERM, EVFILT_SIGNAL, EV_ADD|EV_ENABLE, 0, 0, 0); 418107178Snjl EV_SET(&events[3], targ_fd, EVFILT_READ, EV_ADD|EV_ENABLE, 0, 0, 0); 419107178Snjl if (kevent(kq_fd, events, 4, NULL, 0, NULL) < 0) 420107178Snjl err(1, "kevent signal registration"); 421107178Snjl 422107178Snjl ts.tv_sec = 0; 423107178Snjl ts.tv_nsec = 0; 424107178Snjl tptr = NULL; 425107178Snjl quit = 0; 426107178Snjl 427107178Snjl /* Loop until user signal */ 42844498Sgibbs while (quit == 0) { 429162704Smjacob int retval, i, oo; 430107178Snjl struct ccb_hdr *ccb_h; 43139215Sgibbs 432107178Snjl /* Check for the next signal, read ready, or AIO completion */ 433107178Snjl retval = kevent(kq_fd, NULL, 0, events, MAX_EVENTS, tptr); 434107178Snjl if (retval < 0) { 435107178Snjl if (errno == EINTR) { 436107178Snjl if (debug) 437107178Snjl warnx("EINTR, looping"); 43844498Sgibbs continue; 439107178Snjl } 440107178Snjl else { 441107178Snjl err(1, "kevent failed"); 442107178Snjl } 443107178Snjl } else if (retval > MAX_EVENTS) { 444107178Snjl errx(1, "kevent returned more events than allocated?"); 44539215Sgibbs } 44639215Sgibbs 447107178Snjl /* Process all received events. */ 448162704Smjacob for (oo = i = 0; i < retval; i++) { 449107178Snjl if ((events[i].flags & EV_ERROR) != 0) 450107178Snjl errx(1, "kevent registration failed"); 45139215Sgibbs 452107178Snjl switch (events[i].filter) { 453107178Snjl case EVFILT_READ: 454107178Snjl if (debug) 455107178Snjl warnx("read ready"); 456107178Snjl handle_read(); 457107178Snjl break; 458107178Snjl case EVFILT_AIO: 459107178Snjl { 460107178Snjl struct ccb_scsiio *ctio; 461107178Snjl struct ctio_descr *c_descr; 462107178Snjl if (debug) 463107178Snjl warnx("aio ready"); 46439215Sgibbs 465107178Snjl ctio = (struct ccb_scsiio *)events[i].udata; 466107178Snjl c_descr = (struct ctio_descr *) 467107178Snjl ctio->ccb_h.targ_descr; 468107178Snjl c_descr->event = AIO_DONE; 469107178Snjl /* Queue on the appropriate ATIO */ 470107178Snjl queue_io(ctio); 471107178Snjl /* Process any queued completions. */ 472162704Smjacob oo += run_queue(c_descr->atio); 473107178Snjl break; 474107178Snjl } 475107178Snjl case EVFILT_SIGNAL: 476107178Snjl if (debug) 477107178Snjl warnx("signal ready, setting quit"); 478107178Snjl quit = 1; 479107178Snjl break; 480107178Snjl default: 481162704Smjacob warnx("unknown event %d", events[i].filter); 482107178Snjl break; 483107178Snjl } 484107178Snjl 485107178Snjl if (debug) 486162704Smjacob warnx("event %d done", events[i].filter); 48739215Sgibbs } 48839215Sgibbs 489162704Smjacob if (oo) { 490162704Smjacob tptr = &ts; 491162704Smjacob continue; 492162704Smjacob } 493162704Smjacob 494107178Snjl /* Grab the first CCB and perform one work unit. */ 495107178Snjl if ((ccb_h = TAILQ_FIRST(&work_queue)) != NULL) { 496107178Snjl union ccb *ccb; 49739215Sgibbs 498107178Snjl ccb = (union ccb *)ccb_h; 499107178Snjl switch (ccb_h->func_code) { 500107178Snjl case XPT_ACCEPT_TARGET_IO: 501107178Snjl /* Start one more transfer. */ 502107178Snjl retval = work_atio(&ccb->atio); 503107178Snjl break; 504237825Sken case XPT_IMMEDIATE_NOTIFY: 505237825Sken retval = work_inot(&ccb->cin1); 506107178Snjl break; 507107178Snjl default: 508107178Snjl warnx("Unhandled ccb type %#x on workq", 509107178Snjl ccb_h->func_code); 510107178Snjl abort(); 511107178Snjl /* NOTREACHED */ 51239215Sgibbs } 51339215Sgibbs 514107178Snjl /* Assume work function handled the exception */ 515107178Snjl if ((ccb_h->status & CAM_DEV_QFRZN) != 0) { 516109345Snjl if (debug) { 517109345Snjl warnx("Queue frozen receiving CCB, " 518109345Snjl "releasing"); 519109345Snjl } 520107178Snjl rel_simq(); 52139215Sgibbs } 52239215Sgibbs 523107178Snjl /* No more work needed for this command. */ 524107178Snjl if (retval == 0) { 525107178Snjl TAILQ_REMOVE(&work_queue, ccb_h, 526107178Snjl periph_links.tqe); 52739215Sgibbs } 528107178Snjl } 52939215Sgibbs 530107178Snjl /* 531107178Snjl * Poll for new events (i.e. completions) while we 532107178Snjl * are processing CCBs on the work_queue. Once it's 533107178Snjl * empty, use an infinite wait. 534107178Snjl */ 535107178Snjl if (!TAILQ_EMPTY(&work_queue)) 536107178Snjl tptr = &ts; 537107178Snjl else 538107178Snjl tptr = NULL; 53939215Sgibbs } 54039215Sgibbs} 54139215Sgibbs 542107178Snjl/* CCBs are ready from the kernel */ 54339215Sgibbsstatic void 544107178Snjlhandle_read() 54539215Sgibbs{ 546107178Snjl union ccb *ccb_array[MAX_INITIATORS], *ccb; 547162704Smjacob int ccb_count, i, oo; 54839215Sgibbs 549107178Snjl ccb_count = read(targ_fd, ccb_array, sizeof(ccb_array)); 550107178Snjl if (ccb_count <= 0) { 551107178Snjl warn("read ccb ptrs"); 552107178Snjl return; 55339215Sgibbs } 554107178Snjl ccb_count /= sizeof(union ccb *); 555107178Snjl if (ccb_count < 1) { 556107178Snjl warnx("truncated read ccb ptr?"); 557107178Snjl return; 558107178Snjl } 55939215Sgibbs 560107178Snjl for (i = 0; i < ccb_count; i++) { 561107178Snjl ccb = ccb_array[i]; 562107178Snjl TAILQ_REMOVE(&pending_queue, &ccb->ccb_h, periph_links.tqe); 563107178Snjl 564107178Snjl switch (ccb->ccb_h.func_code) { 565107178Snjl case XPT_ACCEPT_TARGET_IO: 566107178Snjl { 567107178Snjl struct ccb_accept_tio *atio; 568107178Snjl struct atio_descr *a_descr; 569107178Snjl 570107178Snjl /* Initialize ATIO descr for this transaction */ 571107178Snjl atio = &ccb->atio; 572107178Snjl a_descr = (struct atio_descr *)atio->ccb_h.targ_descr; 573107178Snjl bzero(a_descr, sizeof(*a_descr)); 574107178Snjl TAILQ_INIT(&a_descr->cmplt_io); 575107178Snjl a_descr->flags = atio->ccb_h.flags & 576107178Snjl (CAM_DIS_DISCONNECT | CAM_TAG_ACTION_VALID); 577107178Snjl /* XXX add a_descr->priority */ 578107178Snjl if ((atio->ccb_h.flags & CAM_CDB_POINTER) == 0) 579107178Snjl a_descr->cdb = atio->cdb_io.cdb_bytes; 580107178Snjl else 581107178Snjl a_descr->cdb = atio->cdb_io.cdb_ptr; 582107178Snjl 583107178Snjl /* ATIOs are processed in FIFO order */ 584107178Snjl TAILQ_INSERT_TAIL(&work_queue, &ccb->ccb_h, 585107178Snjl periph_links.tqe); 586107178Snjl break; 587107178Snjl } 588107178Snjl case XPT_CONT_TARGET_IO: 589107178Snjl { 590107178Snjl struct ccb_scsiio *ctio; 591107178Snjl struct ctio_descr *c_descr; 592107178Snjl 593107178Snjl ctio = &ccb->ctio; 594107178Snjl c_descr = (struct ctio_descr *)ctio->ccb_h.targ_descr; 595107178Snjl c_descr->event = CTIO_DONE; 596107178Snjl /* Queue on the appropriate ATIO */ 597107178Snjl queue_io(ctio); 598107178Snjl /* Process any queued completions. */ 599162704Smjacob oo += run_queue(c_descr->atio); 600107178Snjl break; 601107178Snjl } 602255562Smav case XPT_IMMEDIATE_NOTIFY: 603107178Snjl /* INOTs are handled with priority */ 604107178Snjl TAILQ_INSERT_HEAD(&work_queue, &ccb->ccb_h, 605107178Snjl periph_links.tqe); 606107178Snjl break; 607107178Snjl default: 608107178Snjl warnx("Unhandled ccb type %#x in handle_read", 609107178Snjl ccb->ccb_h.func_code); 610107178Snjl break; 611107178Snjl } 61239215Sgibbs } 613107178Snjl} 61439215Sgibbs 615107178Snjl/* Process an ATIO CCB from the kernel */ 616107178Snjlint 617107178Snjlwork_atio(struct ccb_accept_tio *atio) 618107178Snjl{ 619107178Snjl struct ccb_scsiio *ctio; 620107178Snjl struct atio_descr *a_descr; 621107178Snjl struct ctio_descr *c_descr; 622107178Snjl cam_status status; 623107178Snjl int ret; 624107178Snjl 625107178Snjl if (debug) 626107178Snjl warnx("Working on ATIO %p", atio); 627107178Snjl 628107178Snjl a_descr = (struct atio_descr *)atio->ccb_h.targ_descr; 629107178Snjl 630107178Snjl /* Get a CTIO and initialize it according to our known parameters */ 631107178Snjl ctio = get_ctio(); 632162704Smjacob if (ctio == NULL) { 633107178Snjl return (1); 634162704Smjacob } 635107178Snjl ret = 0; 636107178Snjl ctio->ccb_h.flags = a_descr->flags; 637107178Snjl ctio->tag_id = atio->tag_id; 638107178Snjl ctio->init_id = atio->init_id; 639107178Snjl /* XXX priority needs to be added to a_descr */ 640107178Snjl c_descr = (struct ctio_descr *)ctio->ccb_h.targ_descr; 641107178Snjl c_descr->atio = atio; 642107178Snjl if ((a_descr->flags & CAM_DIR_IN) != 0) 643107178Snjl c_descr->offset = a_descr->base_off + a_descr->targ_req; 644107178Snjl else if ((a_descr->flags & CAM_DIR_MASK) == CAM_DIR_OUT) 645107178Snjl c_descr->offset = a_descr->base_off + a_descr->init_req; 646120428Ssimokawa else 647120428Ssimokawa c_descr->offset = a_descr->base_off; 648107178Snjl 649107178Snjl /* 650107178Snjl * Return a check condition if there was an error while 651107178Snjl * receiving this ATIO. 652107178Snjl */ 653107178Snjl if (atio->sense_len != 0) { 654226067Sken struct scsi_sense_data_fixed *sense; 65539215Sgibbs 656107178Snjl if (debug) { 657107178Snjl warnx("ATIO with %u bytes sense received", 658107178Snjl atio->sense_len); 65939215Sgibbs } 660237825Sken sense = (struct scsi_sense_data_fixed *)&atio->sense_data; 661107178Snjl tcmd_sense(ctio->init_id, ctio, sense->flags, 662107178Snjl sense->add_sense_code, sense->add_sense_code_qual); 663107178Snjl send_ccb((union ccb *)ctio, /*priority*/1); 664107178Snjl return (0); 665107178Snjl } 66639215Sgibbs 667107178Snjl status = atio->ccb_h.status & CAM_STATUS_MASK; 668107178Snjl switch (status) { 669107178Snjl case CAM_CDB_RECVD: 670107178Snjl ret = tcmd_handle(atio, ctio, ATIO_WORK); 671107178Snjl break; 672107178Snjl case CAM_REQ_ABORTED: 673162704Smjacob warn("ATIO %p aborted", a_descr); 674107178Snjl /* Requeue on HBA */ 675107178Snjl TAILQ_REMOVE(&work_queue, &atio->ccb_h, periph_links.tqe); 676107178Snjl send_ccb((union ccb *)atio, /*priority*/1); 677107178Snjl ret = 1; 678107178Snjl break; 679107178Snjl default: 680107178Snjl warnx("ATIO completed with unhandled status %#x", status); 681107178Snjl abort(); 682107178Snjl /* NOTREACHED */ 683107178Snjl break; 684107178Snjl } 68539215Sgibbs 686107178Snjl return (ret); 687107178Snjl} 68839215Sgibbs 689107178Snjlstatic void 690107178Snjlqueue_io(struct ccb_scsiio *ctio) 691107178Snjl{ 692107178Snjl struct ccb_hdr *ccb_h; 693107178Snjl struct io_queue *ioq; 694162704Smjacob struct ctio_descr *c_descr; 695107178Snjl 696107178Snjl c_descr = (struct ctio_descr *)ctio->ccb_h.targ_descr; 697162704Smjacob if (c_descr->atio == NULL) { 698107178Snjl errx(1, "CTIO %p has NULL ATIO", ctio); 699107178Snjl } 700162704Smjacob ioq = &((struct atio_descr *)c_descr->atio->ccb_h.targ_descr)->cmplt_io; 701107178Snjl 702162704Smjacob if (TAILQ_EMPTY(ioq)) { 703162704Smjacob TAILQ_INSERT_HEAD(ioq, &ctio->ccb_h, periph_links.tqe); 704162704Smjacob return; 705162704Smjacob } 706162704Smjacob 707162704Smjacob TAILQ_FOREACH_REVERSE(ccb_h, ioq, io_queue, periph_links.tqe) { 708162704Smjacob struct ctio_descr *curr_descr = 709162704Smjacob (struct ctio_descr *)ccb_h->targ_descr; 710162704Smjacob if (curr_descr->offset <= c_descr->offset) { 711162704Smjacob break; 71239215Sgibbs } 713162704Smjacob } 714162704Smjacob 715162704Smjacob if (ccb_h) { 716162704Smjacob TAILQ_INSERT_AFTER(ioq, ccb_h, &ctio->ccb_h, periph_links.tqe); 717107178Snjl } else { 718107178Snjl TAILQ_INSERT_HEAD(ioq, &ctio->ccb_h, periph_links.tqe); 719107178Snjl } 720107178Snjl} 72139215Sgibbs 722107178Snjl/* 723107178Snjl * Go through all completed AIO/CTIOs for a given ATIO and advance data 724107178Snjl * counts, start continuation IO, etc. 725107178Snjl */ 726162704Smjacobstatic int 727107178Snjlrun_queue(struct ccb_accept_tio *atio) 728107178Snjl{ 729107178Snjl struct atio_descr *a_descr; 730107178Snjl struct ccb_hdr *ccb_h; 731107178Snjl int sent_status, event; 732107178Snjl 733107178Snjl if (atio == NULL) 734162704Smjacob return (0); 735107178Snjl 736107178Snjl a_descr = (struct atio_descr *)atio->ccb_h.targ_descr; 737107178Snjl 738107178Snjl while ((ccb_h = TAILQ_FIRST(&a_descr->cmplt_io)) != NULL) { 739107178Snjl struct ccb_scsiio *ctio; 740107178Snjl struct ctio_descr *c_descr; 741107178Snjl 742107178Snjl ctio = (struct ccb_scsiio *)ccb_h; 743107178Snjl c_descr = (struct ctio_descr *)ctio->ccb_h.targ_descr; 744107178Snjl 745120428Ssimokawa if (ctio->ccb_h.status == CAM_REQ_ABORTED) { 746120428Ssimokawa TAILQ_REMOVE(&a_descr->cmplt_io, ccb_h, 747120428Ssimokawa periph_links.tqe); 748120428Ssimokawa free_ccb((union ccb *)ctio); 749120428Ssimokawa send_ccb((union ccb *)atio, /*priority*/1); 750120428Ssimokawa continue; 751120428Ssimokawa } 752120428Ssimokawa 753107178Snjl /* If completed item is in range, call handler */ 754107178Snjl if ((c_descr->event == AIO_DONE && 755107178Snjl c_descr->offset == a_descr->base_off + a_descr->targ_ack) 756107178Snjl || (c_descr->event == CTIO_DONE && 757107178Snjl c_descr->offset == a_descr->base_off + a_descr->init_ack)) { 758107178Snjl sent_status = (ccb_h->flags & CAM_SEND_STATUS) != 0; 759107178Snjl event = c_descr->event; 760107178Snjl 761107178Snjl TAILQ_REMOVE(&a_descr->cmplt_io, ccb_h, 762107178Snjl periph_links.tqe); 763107178Snjl tcmd_handle(atio, ctio, c_descr->event); 764107178Snjl 765107178Snjl /* If entire transfer complete, send back ATIO */ 766107178Snjl if (sent_status != 0 && event == CTIO_DONE) 767107178Snjl send_ccb((union ccb *)atio, /*priority*/1); 768107178Snjl } else { 769107178Snjl /* Gap in offsets so wait until later callback */ 770162704Smjacob if (/* debug */ 1) 771162704Smjacob warnx("IO %p:%p out of order %s", ccb_h, 772162704Smjacob a_descr, c_descr->event == AIO_DONE? 773162704Smjacob "aio" : "ctio"); 774162704Smjacob return (1); 77563185Smjacob } 776107178Snjl } 777162704Smjacob return (0); 778107178Snjl} 77963185Smjacob 780107178Snjlstatic int 781237825Skenwork_inot(struct ccb_immediate_notify *inot) 782107178Snjl{ 783107178Snjl cam_status status; 78463185Smjacob 785107178Snjl if (debug) 786107178Snjl warnx("Working on INOT %p", inot); 787107178Snjl 788107178Snjl status = inot->ccb_h.status; 789107178Snjl status &= CAM_STATUS_MASK; 790107178Snjl 791107178Snjl switch (status) { 792107178Snjl case CAM_SCSI_BUS_RESET: 793107178Snjl tcmd_ua(CAM_TARGET_WILDCARD, UA_BUS_RESET); 794107178Snjl abort_all_pending(); 795107178Snjl break; 796107178Snjl case CAM_BDR_SENT: 797107178Snjl tcmd_ua(CAM_TARGET_WILDCARD, UA_BDR); 798107178Snjl abort_all_pending(); 799107178Snjl break; 800107178Snjl case CAM_MESSAGE_RECV: 801237825Sken switch (inot->arg) { 802107178Snjl case MSG_TASK_COMPLETE: 803107178Snjl case MSG_INITIATOR_DET_ERR: 804107178Snjl case MSG_ABORT_TASK_SET: 805107178Snjl case MSG_MESSAGE_REJECT: 806107178Snjl case MSG_NOOP: 807107178Snjl case MSG_PARITY_ERROR: 808107178Snjl case MSG_TARGET_RESET: 809107178Snjl case MSG_ABORT_TASK: 810107178Snjl case MSG_CLEAR_TASK_SET: 811107178Snjl default: 812237825Sken warnx("INOT message %#x", inot->arg); 813107178Snjl break; 81439215Sgibbs } 815107178Snjl break; 816107178Snjl case CAM_REQ_ABORTED: 817107178Snjl warnx("INOT %p aborted", inot); 818107178Snjl break; 819107178Snjl default: 820107178Snjl warnx("Unhandled INOT status %#x", status); 821107178Snjl break; 82239215Sgibbs } 82339215Sgibbs 824107178Snjl /* Requeue on SIM */ 825107178Snjl TAILQ_REMOVE(&work_queue, &inot->ccb_h, periph_links.tqe); 826107178Snjl send_ccb((union ccb *)inot, /*priority*/1); 827107178Snjl 828107178Snjl return (1); 82939215Sgibbs} 83039215Sgibbs 831107178Snjlvoid 832107178Snjlsend_ccb(union ccb *ccb, int priority) 833107178Snjl{ 834107178Snjl if (debug) 835107178Snjl warnx("sending ccb (%#x)", ccb->ccb_h.func_code); 836107178Snjl ccb->ccb_h.pinfo.priority = priority; 837107178Snjl if (XPT_FC_IS_QUEUED(ccb)) { 838107178Snjl TAILQ_INSERT_TAIL(&pending_queue, &ccb->ccb_h, 839107178Snjl periph_links.tqe); 840107178Snjl } 841107178Snjl if (write(targ_fd, &ccb, sizeof(ccb)) != sizeof(ccb)) { 842107178Snjl warn("write ccb"); 843107178Snjl ccb->ccb_h.status = CAM_PROVIDE_FAIL; 844107178Snjl } 845107178Snjl} 846107178Snjl 847107178Snjl/* Return a CTIO/descr/buf combo from the freelist or malloc one */ 848107178Snjlstatic struct ccb_scsiio * 849107178Snjlget_ctio() 850107178Snjl{ 851107178Snjl struct ccb_scsiio *ctio; 852107178Snjl struct ctio_descr *c_descr; 853107178Snjl struct sigevent *se; 854107178Snjl 855162704Smjacob if (num_ctios == MAX_CTIOS) { 856162704Smjacob warnx("at CTIO max"); 857107178Snjl return (NULL); 858162704Smjacob } 859107178Snjl 860107178Snjl ctio = (struct ccb_scsiio *)malloc(sizeof(*ctio)); 861107178Snjl if (ctio == NULL) { 862107178Snjl warn("malloc CTIO"); 863107178Snjl return (NULL); 864107178Snjl } 865107178Snjl c_descr = (struct ctio_descr *)malloc(sizeof(*c_descr)); 866107178Snjl if (c_descr == NULL) { 867107178Snjl free(ctio); 868107178Snjl warn("malloc ctio_descr"); 869107178Snjl return (NULL); 870107178Snjl } 871107178Snjl c_descr->buf = malloc(buf_size); 872107178Snjl if (c_descr->buf == NULL) { 873107178Snjl free(c_descr); 874107178Snjl free(ctio); 875107178Snjl warn("malloc backing store"); 876107178Snjl return (NULL); 877107178Snjl } 878107178Snjl num_ctios++; 879107178Snjl 880107178Snjl /* Initialize CTIO, CTIO descr, and AIO */ 881107178Snjl ctio->ccb_h.func_code = XPT_CONT_TARGET_IO; 882107178Snjl ctio->ccb_h.retry_count = 2; 883109345Snjl ctio->ccb_h.timeout = CAM_TIME_INFINITY; 884107178Snjl ctio->data_ptr = c_descr->buf; 885107178Snjl ctio->ccb_h.targ_descr = c_descr; 886107178Snjl c_descr->aiocb.aio_buf = c_descr->buf; 887107178Snjl c_descr->aiocb.aio_fildes = file_fd; 888107178Snjl se = &c_descr->aiocb.aio_sigevent; 889107178Snjl se->sigev_notify = SIGEV_KEVENT; 890107178Snjl se->sigev_notify_kqueue = kq_fd; 891157009Smjacob se->sigev_value.sival_ptr = ctio; 892107178Snjl 893107178Snjl return (ctio); 894107178Snjl} 895107178Snjl 896107178Snjlvoid 897107178Snjlfree_ccb(union ccb *ccb) 898107178Snjl{ 899107178Snjl switch (ccb->ccb_h.func_code) { 900107178Snjl case XPT_CONT_TARGET_IO: 901107178Snjl { 902107178Snjl struct ctio_descr *c_descr; 903107178Snjl 904107178Snjl c_descr = (struct ctio_descr *)ccb->ccb_h.targ_descr; 905107178Snjl free(c_descr->buf); 906107178Snjl num_ctios--; 907107178Snjl /* FALLTHROUGH */ 908107178Snjl } 909107178Snjl case XPT_ACCEPT_TARGET_IO: 910107178Snjl free(ccb->ccb_h.targ_descr); 911107178Snjl /* FALLTHROUGH */ 912255562Smav case XPT_IMMEDIATE_NOTIFY: 913107178Snjl default: 914107178Snjl free(ccb); 915107178Snjl break; 916107178Snjl } 917107178Snjl} 918107178Snjl 919107178Snjlstatic cam_status 920107178Snjlget_sim_flags(u_int16_t *flags) 921107178Snjl{ 922107178Snjl struct ccb_pathinq cpi; 923107178Snjl cam_status status; 924107178Snjl 925107178Snjl /* Find SIM capabilities */ 926107178Snjl bzero(&cpi, sizeof(cpi)); 927107178Snjl cpi.ccb_h.func_code = XPT_PATH_INQ; 928107178Snjl send_ccb((union ccb *)&cpi, /*priority*/1); 929107178Snjl status = cpi.ccb_h.status & CAM_STATUS_MASK; 930107178Snjl if (status != CAM_REQ_CMP) { 931107178Snjl fprintf(stderr, "CPI failed, status %#x\n", status); 932107178Snjl return (status); 933107178Snjl } 934107178Snjl 935107178Snjl /* Can only enable on controllers that support target mode */ 936107178Snjl if ((cpi.target_sprt & PIT_PROCESSOR) == 0) { 937107178Snjl fprintf(stderr, "HBA does not support target mode\n"); 938107178Snjl status = CAM_PATH_INVALID; 939107178Snjl return (status); 940107178Snjl } 941107178Snjl 942107178Snjl *flags = cpi.hba_inquiry; 943107178Snjl return (status); 944107178Snjl} 945107178Snjl 94639215Sgibbsstatic void 947107178Snjlrel_simq() 94844498Sgibbs{ 949107178Snjl struct ccb_relsim crs; 950107178Snjl 951107178Snjl bzero(&crs, sizeof(crs)); 952107178Snjl crs.ccb_h.func_code = XPT_REL_SIMQ; 953107178Snjl crs.release_flags = RELSIM_RELEASE_AFTER_QEMPTY; 954107178Snjl crs.openings = 0; 955107178Snjl crs.release_timeout = 0; 956107178Snjl crs.qfrozen_cnt = 0; 957107178Snjl send_ccb((union ccb *)&crs, /*priority*/0); 95844498Sgibbs} 95944498Sgibbs 960107178Snjl/* Cancel all pending CCBs. */ 96144498Sgibbsstatic void 962107178Snjlabort_all_pending() 96339215Sgibbs{ 964107178Snjl struct ccb_abort cab; 965107178Snjl struct ccb_hdr *ccb_h; 96639215Sgibbs 967107178Snjl if (debug) 968107178Snjl warnx("abort_all_pending"); 96939215Sgibbs 970107178Snjl bzero(&cab, sizeof(cab)); 971107178Snjl cab.ccb_h.func_code = XPT_ABORT; 972107178Snjl TAILQ_FOREACH(ccb_h, &pending_queue, periph_links.tqe) { 973107178Snjl if (debug) 974107178Snjl warnx("Aborting pending CCB %p\n", ccb_h); 975107178Snjl cab.abort_ccb = (union ccb *)ccb_h; 976107178Snjl send_ccb((union ccb *)&cab, /*priority*/1); 977107178Snjl if (cab.ccb_h.status != CAM_REQ_CMP) { 978107178Snjl warnx("Unable to abort CCB, status %#x\n", 979107178Snjl cab.ccb_h.status); 980107178Snjl } 981107178Snjl } 98239215Sgibbs} 98339215Sgibbs 984107178Snjlstatic void 985107178Snjlusage() 986107178Snjl{ 987107178Snjl fprintf(stderr, 988162704Smjacob "Usage: scsi_target [-AdSTY] [-b bufsize] [-c sectorsize]\n" 989107178Snjl "\t\t[-r numbufs] [-s volsize] [-W 8,16,32]\n" 990107178Snjl "\t\tbus:target:lun filename\n"); 991107178Snjl exit(1); 992107178Snjl} 993