scsi_target.c revision 44498
1265236Sken/* 2265236Sken * Sample program to attach to the "targ" processor target, target mode 3265236Sken * peripheral driver and push or receive data. 4265236Sken * 5265236Sken * Copyright (c) 1998 Justin T. Gibbs. 6265236Sken * All rights reserved. 7265236Sken * 8265236Sken * Redistribution and use in source and binary forms, with or without 9265236Sken * modification, are permitted provided that the following conditions 10265236Sken * are met: 11265236Sken * 1. Redistributions of source code must retain the above copyright 12265236Sken * notice, this list of conditions, and the following disclaimer, 13265236Sken * without modification, immediately at the beginning of the file. 14265236Sken * 2. The name of the author may not be used to endorse or promote products 15265236Sken * derived from this software without specific prior written permission. 16265236Sken * 17265236Sken * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18265236Sken * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19265236Sken * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20265236Sken * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 21265236Sken * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22265236Sken * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23265236Sken * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24265236Sken * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25265236Sken * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26265236Sken * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27265236Sken * SUCH DAMAGE. 28265236Sken * 29265236Sken * $Id: scsi_target.c,v 1.2 1998/12/10 04:00:03 gibbs Exp $ 30265236Sken */ 31265236Sken 32265236Sken#include <sys/types.h> 33265236Sken 34265236Sken#include <errno.h> 35265236Sken#include <fcntl.h> 36265236Sken#include <poll.h> 37265236Sken#include <signal.h> 38265236Sken#include <stddef.h> 39265236Sken#include <stdio.h> 40265236Sken#include <stdlib.h> 41265236Sken#include <sysexits.h> 42265236Sken#include <unistd.h> 43265236Sken 44265236Sken#include <cam/scsi/scsi_all.h> 45265236Sken#include <cam/scsi/scsi_message.h> 46265236Sken#include <cam/scsi/scsi_targetio.h> 47265236Sken 48265236Skenchar *appname; 49265236Skenint ifd; 50265236Skenchar *ifilename; 51265236Skenint ofd; 52265236Skenchar *ofilename; 53265236Skensize_t bufsize = 64 * 1024; 54265236Skenvoid *buf; 55265236Skenchar targdevname[80]; 56265236Skenint targctlfd; 57265236Skenint targfd; 58265236Skenint quit; 59265236Skenstruct ioc_alloc_unit alloc_unit = { 60265236Sken CAM_BUS_WILDCARD, 61265236Sken CAM_TARGET_WILDCARD, 62265236Sken CAM_LUN_WILDCARD 63265236Sken}; 64265236Sken 65265236Skenstatic void pump_events(); 66265236Skenstatic void handle_exception(); 67265236Skenstatic void quit_handler(); 68265236Skenstatic void usage(); 69265236Sken 70265236Skenint 71265236Skenmain(int argc, char *argv[]) 72265236Sken{ 73265236Sken int ch; 74265236Sken 75265236Sken appname = *argv; 76265236Sken while ((ch = getopt(argc, argv, "i:o:p:t:l:")) != -1) { 77265236Sken switch(ch) { 78265236Sken case 'i': 79265236Sken if ((ifd = open(optarg, O_RDONLY)) == -1) { 80265236Sken perror(optarg); 81265236Sken exit(EX_NOINPUT); 82265236Sken } 83265236Sken ifilename = optarg; 84265236Sken break; 85265236Sken case 'o': 86265236Sken if ((ofd = open(optarg, 87265236Sken O_WRONLY|O_CREAT), 0600) == -1) { 88265236Sken perror(optarg); 89265236Sken exit(EX_CANTCREAT); 90265236Sken } 91265236Sken ofilename = optarg; 92265236Sken break; 93265236Sken case 'p': 94265236Sken alloc_unit.path_id = atoi(optarg); 95265236Sken break; 96265236Sken case 't': 97265236Sken alloc_unit.target_id = atoi(optarg); 98265236Sken break; 99265236Sken case 'l': 100265236Sken alloc_unit.lun_id = atoi(optarg); 101265236Sken break; 102265236Sken case '?': 103265236Sken default: 104265236Sken usage(); 105265236Sken /* NOTREACHED */ 106265236Sken } 107265236Sken } 108265236Sken argc -= optind; 109265236Sken argv += optind; 110265236Sken 111265236Sken if (alloc_unit.path_id == CAM_BUS_WILDCARD 112265236Sken || alloc_unit.target_id == CAM_TARGET_WILDCARD 113265236Sken || alloc_unit.lun_id == CAM_LUN_WILDCARD) { 114265236Sken fprintf(stderr, "%s: Incomplete device path specifiled\n", 115265236Sken appname); 116265236Sken usage(); 117265236Sken /* NOTREACHED */ 118265236Sken } 119265236Sken 120265236Sken if (argc != 0) { 121265236Sken fprintf(stderr, "%s: Too many arguments\n", appname); 122265236Sken usage(); 123265236Sken /* NOTREACHED */ 124265236Sken } 125265236Sken 126265236Sken /* Allocate a new instance */ 127265236Sken if ((targctlfd = open("/dev/targ.ctl", O_RDWR)) == -1) { 128265236Sken perror("/dev/targ.ctl"); 129265236Sken exit(EX_UNAVAILABLE); 130265236Sken } 131265236Sken 132265236Sken if (ioctl(targctlfd, TARGCTLIOALLOCUNIT, &alloc_unit) == -1) { 133265236Sken perror("TARGCTLIOALLOCUNIT"); 134265236Sken exit(EX_SOFTWARE); 135265236Sken } 136265236Sken 137265236Sken snprintf(targdevname, sizeof(targdevname), "/dev/targ%d", 138265236Sken alloc_unit.unit); 139265236Sken 140265236Sken if ((targfd = open(targdevname, O_RDWR)) == -1) { 141265236Sken perror(targdevname); 142265236Sken ioctl(targctlfd, TARGCTLIOFREEUNIT, &alloc_unit); 143265236Sken exit(EX_NOINPUT); 144265236Sken } 145265236Sken 146265236Sken buf = malloc(bufsize); 147265236Sken 148265236Sken if (buf == NULL) { 149265236Sken fprintf(stderr, "%s: Could not malloc I/O buffer", appname); 150265236Sken exit(EX_OSERR); 151265236Sken } 152265236Sken 153265236Sken signal(SIGHUP, quit_handler); 154265236Sken signal(SIGINT, quit_handler); 155265236Sken signal(SIGTERM, quit_handler); 156265236Sken 157265236Sken pump_events(); 158265236Sken 159265236Sken close(targfd); 160265236Sken 161265236Sken if (ioctl(targctlfd, TARGCTLIOFREEUNIT, &alloc_unit) == -1) { 162265236Sken perror("TARGCTLIOFREEUNIT"); 163265236Sken exit(EX_SOFTWARE); 164265236Sken } 165265236Sken 166265236Sken close(targctlfd); 167265236Sken return (0); 168265236Sken} 169265236Sken 170265236Skenstatic void 171265236Skenpump_events() 172265236Sken{ 173265236Sken struct pollfd targpoll; 174265236Sken 175265236Sken targpoll.fd = targfd; 176265236Sken targpoll.events = POLLRDNORM|POLLWRNORM; 177265236Sken 178265236Sken while (quit == 0) { 179265236Sken int retval; 180265236Sken 181265236Sken retval = poll(&targpoll, 1, INFTIM); 182265236Sken 183265236Sken if (retval == -1) { 184265236Sken if (errno == EINTR) 185265236Sken continue; 186265236Sken perror("Poll Failed"); 187265236Sken exit(EX_SOFTWARE); 188265236Sken } 189265236Sken 190265236Sken if (retval == 0) { 191265236Sken perror("Poll returned 0 although timeout infinite???"); 192265236Sken exit(EX_SOFTWARE); 193265236Sken } 194265236Sken 195265236Sken if (retval > 1) { 196265236Sken perror("Poll returned more fds ready than allocated"); 197265236Sken exit(EX_SOFTWARE); 198265236Sken } 199265236Sken 200265236Sken /* Process events */ 201265236Sken if ((targpoll.revents & POLLERR) != 0) { 202265236Sken handle_exception(); 203265236Sken } 204265236Sken 205265236Sken if ((targpoll.revents & POLLRDNORM) != 0) { 206265236Sken retval = read(targfd, buf, bufsize); 207265236Sken 208265236Sken if (retval == -1) { 209265236Sken perror("Read from targ failed"); 210265236Sken } else { 211265236Sken retval = write(ofd, buf, retval); 212265236Sken if (retval == -1) { 213265236Sken perror("Write to file failed"); 214265236Sken } 215265236Sken } 216265236Sken } 217265236Sken 218265236Sken if ((targpoll.revents & POLLWRNORM) != 0) { 219265236Sken int amount_read; 220265236Sken 221265236Sken retval = read(ifd, buf, bufsize); 222265236Sken if (retval == -1) { 223265236Sken perror("Read from file failed"); 224265236Sken exit(EX_SOFTWARE); 225265236Sken } 226265236Sken 227265236Sken amount_read = retval; 228265236Sken retval = write(targfd, buf, retval); 229265236Sken if (retval == -1) { 230265236Sken perror("Write to targ failed"); 231265236Sken retval = 0; 232265236Sken } 233265236Sken 234265236Sken /* Backup in our input stream on short writes */ 235265236Sken if (retval != amount_read) 236265236Sken lseek(ifd, retval - amount_read, SEEK_CUR); 237265236Sken } 238265236Sken } 239265236Sken} 240265236Sken 241265236Skenstatic void 242265236Skenhandle_exception() 243265236Sken{ 244265236Sken targ_exception exceptions; 245265236Sken 246265236Sken if (ioctl(targfd, TARGIOCFETCHEXCEPTION, &exceptions) == -1) { 247265236Sken perror("TARGIOCFETCHEXCEPTION"); 248265236Sken exit(EX_SOFTWARE); 249265236Sken } 250265236Sken 251265236Sken if ((exceptions & TARG_EXCEPT_DEVICE_INVALID) != 0) { 252265236Sken /* Device went away. Nothing more to do. */ 253265236Sken exit(0); 254265236Sken } 255265236Sken 256265236Sken if ((exceptions & TARG_EXCEPT_UNKNOWN_ATIO) != 0) { 257265236Sken struct ccb_accept_tio atio; 258265236Sken struct ioc_initiator_state ioc_istate; 259265236Sken struct scsi_sense_data *sense; 260265236Sken union ccb ccb; 261265236Sken 262265236Sken if (ioctl(targfd, TARGIOCFETCHATIO, &atio) == -1) { 263265236Sken perror("TARGIOCFETCHATIO"); 264265236Sken exit(EX_SOFTWARE); 265265236Sken } 266265236Sken 267265236Sken printf("Ignoring unhandled command 0x%x for Id %d\n", 268265236Sken atio.cdb_io.cdb_bytes[0], atio.init_id); 269265236Sken 270265236Sken ioc_istate.initiator_id = atio.init_id; 271265236Sken if (ioctl(targfd, TARGIOCGETISTATE, &ioc_istate) == -1) { 272265236Sken perror("TARGIOCGETISTATE"); 273265236Sken exit(EX_SOFTWARE); 274265236Sken } 275265236Sken 276265236Sken /* Send back Illegal Command code status */ 277265236Sken ioc_istate.istate.pending_ca |= CA_CMD_SENSE; 278265236Sken sense = &ioc_istate.istate.sense_data; 279265236Sken bzero(sense, sizeof(*sense)); 280265236Sken sense->error_code = SSD_CURRENT_ERROR; 281265236Sken sense->flags = SSD_KEY_ILLEGAL_REQUEST; 282265236Sken sense->add_sense_code = 0x20; 283265236Sken sense->add_sense_code_qual = 0x00; 284265236Sken sense->extra_len = offsetof(struct scsi_sense_data, fru) 285265236Sken - offsetof(struct scsi_sense_data, extra_len); 286265236Sken 287265236Sken if (ioctl(targfd, TARGIOCSETISTATE, &ioc_istate) == -1) { 288265236Sken perror("TARGIOCSETISTATE"); 289265236Sken exit(EX_SOFTWARE); 290265236Sken } 291265236Sken 292265236Sken bzero(&ccb, sizeof(ccb)); 293265236Sken cam_fill_ctio(&ccb.csio, /*retries*/2, 294265236Sken /*cbfcnp*/NULL, 295265236Sken /*flags*/CAM_DIR_NONE 296265236Sken | (atio.ccb_h.flags & CAM_TAG_ACTION_VALID) 297265236Sken | CAM_SEND_STATUS, 298265236Sken /*tag_action*/MSG_SIMPLE_Q_TAG, 299265236Sken atio.tag_id, 300265236Sken atio.init_id, 301265236Sken SCSI_STATUS_CHECK_COND, 302265236Sken /*data_ptr*/NULL, 303265236Sken /*dxfer_len*/0, 304265236Sken /*timeout*/5 * 1000); 305265236Sken if (ioctl(targfd, TARGIOCCOMMAND, &ccb) == -1) { 306265236Sken perror("TARGIOCCOMMAND"); 307265236Sken exit(EX_SOFTWARE); 308265236Sken } 309265236Sken 310265236Sken } 311265236Sken 312265236Sken if (ioctl(targfd, TARGIOCCLEAREXCEPTION, &exceptions) == -1) { 313265236Sken perror("TARGIOCCLEAREXCEPTION"); 314265236Sken exit(EX_SOFTWARE); 315265236Sken } 316265236Sken} 317265236Sken 318265236Skenstatic void 319265236Skenquit_handler(int signum) 320265236Sken{ 321265236Sken quit = 1; 322265236Sken} 323265236Sken 324265236Skenstatic void 325265236Skenusage() 326265236Sken{ 327265236Sken 328265236Sken (void)fprintf(stderr, 329265236Sken"usage: %-16s [-o output_file] [-i input_file] -p path -t target -l lun\n", 330265236Sken appname); 331265236Sken 332265236Sken exit(EX_USAGE); 333265236Sken} 334265236Sken 335265236Sken