scsi_target.c revision 44498
1/* 2 * Sample program to attach to the "targ" processor target, target mode 3 * peripheral driver and push or receive data. 4 * 5 * Copyright (c) 1998 Justin T. Gibbs. 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. 14 * 2. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 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 * 29 * $Id: scsi_target.c,v 1.2 1998/12/10 04:00:03 gibbs Exp $ 30 */ 31 32#include <sys/types.h> 33 34#include <errno.h> 35#include <fcntl.h> 36#include <poll.h> 37#include <signal.h> 38#include <stddef.h> 39#include <stdio.h> 40#include <stdlib.h> 41#include <sysexits.h> 42#include <unistd.h> 43 44#include <cam/scsi/scsi_all.h> 45#include <cam/scsi/scsi_message.h> 46#include <cam/scsi/scsi_targetio.h> 47 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; 59struct ioc_alloc_unit alloc_unit = { 60 CAM_BUS_WILDCARD, 61 CAM_TARGET_WILDCARD, 62 CAM_LUN_WILDCARD 63}; 64 65static void pump_events(); 66static void handle_exception(); 67static void quit_handler(); 68static void usage(); 69 70int 71main(int argc, char *argv[]) 72{ 73 int ch; 74 75 appname = *argv; 76 while ((ch = getopt(argc, argv, "i:o:p:t:l:")) != -1) { 77 switch(ch) { 78 case 'i': 79 if ((ifd = open(optarg, O_RDONLY)) == -1) { 80 perror(optarg); 81 exit(EX_NOINPUT); 82 } 83 ifilename = optarg; 84 break; 85 case 'o': 86 if ((ofd = open(optarg, 87 O_WRONLY|O_CREAT), 0600) == -1) { 88 perror(optarg); 89 exit(EX_CANTCREAT); 90 } 91 ofilename = optarg; 92 break; 93 case 'p': 94 alloc_unit.path_id = atoi(optarg); 95 break; 96 case 't': 97 alloc_unit.target_id = atoi(optarg); 98 break; 99 case 'l': 100 alloc_unit.lun_id = atoi(optarg); 101 break; 102 case '?': 103 default: 104 usage(); 105 /* NOTREACHED */ 106 } 107 } 108 argc -= optind; 109 argv += optind; 110 111 if (alloc_unit.path_id == CAM_BUS_WILDCARD 112 || alloc_unit.target_id == CAM_TARGET_WILDCARD 113 || alloc_unit.lun_id == CAM_LUN_WILDCARD) { 114 fprintf(stderr, "%s: Incomplete device path specifiled\n", 115 appname); 116 usage(); 117 /* NOTREACHED */ 118 } 119 120 if (argc != 0) { 121 fprintf(stderr, "%s: Too many arguments\n", appname); 122 usage(); 123 /* NOTREACHED */ 124 } 125 126 /* Allocate a new instance */ 127 if ((targctlfd = open("/dev/targ.ctl", O_RDWR)) == -1) { 128 perror("/dev/targ.ctl"); 129 exit(EX_UNAVAILABLE); 130 } 131 132 if (ioctl(targctlfd, TARGCTLIOALLOCUNIT, &alloc_unit) == -1) { 133 perror("TARGCTLIOALLOCUNIT"); 134 exit(EX_SOFTWARE); 135 } 136 137 snprintf(targdevname, sizeof(targdevname), "/dev/targ%d", 138 alloc_unit.unit); 139 140 if ((targfd = open(targdevname, O_RDWR)) == -1) { 141 perror(targdevname); 142 ioctl(targctlfd, TARGCTLIOFREEUNIT, &alloc_unit); 143 exit(EX_NOINPUT); 144 } 145 146 buf = malloc(bufsize); 147 148 if (buf == NULL) { 149 fprintf(stderr, "%s: Could not malloc I/O buffer", appname); 150 exit(EX_OSERR); 151 } 152 153 signal(SIGHUP, quit_handler); 154 signal(SIGINT, quit_handler); 155 signal(SIGTERM, quit_handler); 156 157 pump_events(); 158 159 close(targfd); 160 161 if (ioctl(targctlfd, TARGCTLIOFREEUNIT, &alloc_unit) == -1) { 162 perror("TARGCTLIOFREEUNIT"); 163 exit(EX_SOFTWARE); 164 } 165 166 close(targctlfd); 167 return (0); 168} 169 170static void 171pump_events() 172{ 173 struct pollfd targpoll; 174 175 targpoll.fd = targfd; 176 targpoll.events = POLLRDNORM|POLLWRNORM; 177 178 while (quit == 0) { 179 int retval; 180 181 retval = poll(&targpoll, 1, INFTIM); 182 183 if (retval == -1) { 184 if (errno == EINTR) 185 continue; 186 perror("Poll Failed"); 187 exit(EX_SOFTWARE); 188 } 189 190 if (retval == 0) { 191 perror("Poll returned 0 although timeout infinite???"); 192 exit(EX_SOFTWARE); 193 } 194 195 if (retval > 1) { 196 perror("Poll returned more fds ready than allocated"); 197 exit(EX_SOFTWARE); 198 } 199 200 /* Process events */ 201 if ((targpoll.revents & POLLERR) != 0) { 202 handle_exception(); 203 } 204 205 if ((targpoll.revents & POLLRDNORM) != 0) { 206 retval = read(targfd, buf, bufsize); 207 208 if (retval == -1) { 209 perror("Read from targ failed"); 210 } else { 211 retval = write(ofd, buf, retval); 212 if (retval == -1) { 213 perror("Write to file failed"); 214 } 215 } 216 } 217 218 if ((targpoll.revents & POLLWRNORM) != 0) { 219 int amount_read; 220 221 retval = read(ifd, buf, bufsize); 222 if (retval == -1) { 223 perror("Read from file failed"); 224 exit(EX_SOFTWARE); 225 } 226 227 amount_read = retval; 228 retval = write(targfd, buf, retval); 229 if (retval == -1) { 230 perror("Write to targ failed"); 231 retval = 0; 232 } 233 234 /* Backup in our input stream on short writes */ 235 if (retval != amount_read) 236 lseek(ifd, retval - amount_read, SEEK_CUR); 237 } 238 } 239} 240 241static void 242handle_exception() 243{ 244 targ_exception exceptions; 245 246 if (ioctl(targfd, TARGIOCFETCHEXCEPTION, &exceptions) == -1) { 247 perror("TARGIOCFETCHEXCEPTION"); 248 exit(EX_SOFTWARE); 249 } 250 251 if ((exceptions & TARG_EXCEPT_DEVICE_INVALID) != 0) { 252 /* Device went away. Nothing more to do. */ 253 exit(0); 254 } 255 256 if ((exceptions & TARG_EXCEPT_UNKNOWN_ATIO) != 0) { 257 struct ccb_accept_tio atio; 258 struct ioc_initiator_state ioc_istate; 259 struct scsi_sense_data *sense; 260 union ccb ccb; 261 262 if (ioctl(targfd, TARGIOCFETCHATIO, &atio) == -1) { 263 perror("TARGIOCFETCHATIO"); 264 exit(EX_SOFTWARE); 265 } 266 267 printf("Ignoring unhandled command 0x%x for Id %d\n", 268 atio.cdb_io.cdb_bytes[0], atio.init_id); 269 270 ioc_istate.initiator_id = atio.init_id; 271 if (ioctl(targfd, TARGIOCGETISTATE, &ioc_istate) == -1) { 272 perror("TARGIOCGETISTATE"); 273 exit(EX_SOFTWARE); 274 } 275 276 /* Send back Illegal Command code status */ 277 ioc_istate.istate.pending_ca |= CA_CMD_SENSE; 278 sense = &ioc_istate.istate.sense_data; 279 bzero(sense, sizeof(*sense)); 280 sense->error_code = SSD_CURRENT_ERROR; 281 sense->flags = SSD_KEY_ILLEGAL_REQUEST; 282 sense->add_sense_code = 0x20; 283 sense->add_sense_code_qual = 0x00; 284 sense->extra_len = offsetof(struct scsi_sense_data, fru) 285 - offsetof(struct scsi_sense_data, extra_len); 286 287 if (ioctl(targfd, TARGIOCSETISTATE, &ioc_istate) == -1) { 288 perror("TARGIOCSETISTATE"); 289 exit(EX_SOFTWARE); 290 } 291 292 bzero(&ccb, sizeof(ccb)); 293 cam_fill_ctio(&ccb.csio, /*retries*/2, 294 /*cbfcnp*/NULL, 295 /*flags*/CAM_DIR_NONE 296 | (atio.ccb_h.flags & CAM_TAG_ACTION_VALID) 297 | CAM_SEND_STATUS, 298 /*tag_action*/MSG_SIMPLE_Q_TAG, 299 atio.tag_id, 300 atio.init_id, 301 SCSI_STATUS_CHECK_COND, 302 /*data_ptr*/NULL, 303 /*dxfer_len*/0, 304 /*timeout*/5 * 1000); 305 if (ioctl(targfd, TARGIOCCOMMAND, &ccb) == -1) { 306 perror("TARGIOCCOMMAND"); 307 exit(EX_SOFTWARE); 308 } 309 310 } 311 312 if (ioctl(targfd, TARGIOCCLEAREXCEPTION, &exceptions) == -1) { 313 perror("TARGIOCCLEAREXCEPTION"); 314 exit(EX_SOFTWARE); 315 } 316} 317 318static void 319quit_handler(int signum) 320{ 321 quit = 1; 322} 323 324static void 325usage() 326{ 327 328 (void)fprintf(stderr, 329"usage: %-16s [-o output_file] [-i input_file] -p path -t target -l lun\n", 330 appname); 331 332 exit(EX_USAGE); 333} 334 335