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 * $FreeBSD$ 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 48 char *appname; 49 int ifd; 50 char *ifilename; 51 int ofd; 52 char *ofilename; 53 size_t bufsize = 64 * 1024; 54 void *buf; 55 char targdevname[80]; 56 int targctlfd; 57 int targfd; 58 int quit; 59 struct ioc_alloc_unit alloc_unit = { 60 CAM_BUS_WILDCARD, 61 CAM_TARGET_WILDCARD, 62 CAM_LUN_WILDCARD 63 }; 64 65 static void pump_events(); 66 static void cleanup(); 67 static void handle_exception(); 68 static void quit_handler(); 69 static void usage(); 70 71 int 72 main(int argc, char *argv[]) 73 { 74 int ch; 75 76 appname = *argv; 77 while ((ch = getopt(argc, argv, "i:o:p:t:l:")) != -1) { 78 switch(ch) { 79 case 'i': 80 if ((ifd = open(optarg, O_RDONLY)) == -1) { 81 perror(optarg); 82 exit(EX_NOINPUT); 83 } 84 ifilename = optarg; 85 break; 86 case 'o': 87 if ((ofd = open(optarg, 88 O_WRONLY|O_CREAT), 0600) == -1) { 89 perror(optarg); 90 exit(EX_CANTCREAT); 91 } 92 ofilename = optarg; 93 break; 94 case 'p': 95 alloc_unit.path_id = atoi(optarg); 96 break; 97 case 't': 98 alloc_unit.target_id = atoi(optarg); 99 break; 100 case 'l': 101 alloc_unit.lun_id = atoi(optarg); 102 break; 103 case '?': 104 default: 105 usage(); 106 /* NOTREACHED */ 107 } 108 } 109 argc -= optind; 110 argv += optind; 111 112 if (alloc_unit.path_id == CAM_BUS_WILDCARD 113 || alloc_unit.target_id == CAM_TARGET_WILDCARD 114 || alloc_unit.lun_id == CAM_LUN_WILDCARD) { 115 fprintf(stderr, "%s: Incomplete device path specifiled\n", 116 appname); 117 usage(); 118 /* NOTREACHED */ 119 } 120 121 if (argc != 0) { 122 fprintf(stderr, "%s: Too many arguments\n", appname); 123 usage(); 124 /* NOTREACHED */ 125 } 126 127 /* Allocate a new instance */ 128 if ((targctlfd = open("/dev/targ.ctl", O_RDWR)) == -1) { 129 perror("/dev/targ.ctl"); 130 exit(EX_UNAVAILABLE); 131 } 132 133 if (ioctl(targctlfd, TARGCTLIOALLOCUNIT, &alloc_unit) == -1) { 134 perror("TARGCTLIOALLOCUNIT"); 135 exit(EX_SOFTWARE); 136 } 137 138 snprintf(targdevname, sizeof(targdevname), "/dev/targ%d", 139 alloc_unit.unit); 140 141 if ((targfd = open(targdevname, O_RDWR)) == -1) { 142 perror(targdevname); 143 ioctl(targctlfd, TARGCTLIOFREEUNIT, &alloc_unit); 144 exit(EX_NOINPUT); 145 } 146 147 buf = malloc(bufsize); 148 149 if (buf == NULL) { 150 fprintf(stderr, "%s: Could not malloc I/O buffer", appname); 151 exit(EX_OSERR); 152 } 153 154 signal(SIGHUP, quit_handler); 155 signal(SIGINT, quit_handler); 156 signal(SIGTERM, quit_handler); 157 158 atexit(cleanup); 159 160 pump_events(); 161 162 return (0); 163 } 164 165 static void 166 cleanup() 167 { 168 close(targfd); 169 170 if (ioctl(targctlfd, TARGCTLIOFREEUNIT, &alloc_unit) == -1) { 171 perror("TARGCTLIOFREEUNIT"); 172 exit(EX_SOFTWARE); 173 } 174 175 close(targctlfd); 176 } 177 178 static void 179 pump_events() 180 { 181 struct pollfd targpoll; 182 183 targpoll.fd = targfd; 184 targpoll.events = POLLRDNORM|POLLWRNORM; 185 186 while (quit == 0) { 187 int retval; 188 189 retval = poll(&targpoll, 1, INFTIM); 190 191 if (retval == -1) { 192 if (errno == EINTR) 193 continue; 194 perror("Poll Failed"); 195 exit(EX_SOFTWARE); 196 } 197 198 if (retval == 0) { 199 perror("Poll returned 0 although timeout infinite???"); 200 exit(EX_SOFTWARE); 201 } 202 203 if (retval > 1) { 204 perror("Poll returned more fds ready than allocated"); 205 exit(EX_SOFTWARE); 206 } 207 208 /* Process events */ 209 if ((targpoll.revents & POLLERR) != 0) { 210 handle_exception(); 211 } 212 213 if ((targpoll.revents & POLLRDNORM) != 0) { 214 retval = read(targfd, buf, bufsize); 215 216 if (retval == -1) { 217 perror("Read from targ failed"); 218 /* Go look for exceptions */ 219 continue; 220 } else { 221 retval = write(ofd, buf, retval); 222 if (retval == -1) { 223 perror("Write to file failed"); 224 } 225 } 226 } 227 228 if ((targpoll.revents & POLLWRNORM) != 0) { 229 int amount_read; 230 231 retval = read(ifd, buf, bufsize); 232 if (retval == -1) { 233 perror("Read from file failed"); 234 exit(EX_SOFTWARE); 235 } 236 237 amount_read = retval; 238 retval = write(targfd, buf, retval); 239 if (retval == -1) { 240 perror("Write to targ failed"); 241 retval = 0; 242 } 243 244 /* Backup in our input stream on short writes */ 245 if (retval != amount_read) 246 lseek(ifd, retval - amount_read, SEEK_CUR); 247 } 248 } 249 } 250 251 static void 252 handle_exception() 253 { 254 targ_exception exceptions; 255 256 if (ioctl(targfd, TARGIOCFETCHEXCEPTION, &exceptions) == -1) { 257 perror("TARGIOCFETCHEXCEPTION"); 258 exit(EX_SOFTWARE); 259 } 260 261 printf("Saw exceptions %x\n", exceptions); 262 if ((exceptions & TARG_EXCEPT_DEVICE_INVALID) != 0) { 263 /* Device went away. Nothing more to do. */ 264 printf("Device went away\n"); 265 exit(0); 266 } 267 268 if ((exceptions & TARG_EXCEPT_UNKNOWN_ATIO) != 0) { 269 struct ccb_accept_tio atio; 270 struct ioc_initiator_state ioc_istate; 271 struct scsi_sense_data *sense; 272 union ccb ccb; 273 274 if (ioctl(targfd, TARGIOCFETCHATIO, &atio) == -1) { 275 perror("TARGIOCFETCHATIO"); 276 exit(EX_SOFTWARE); 277 } 278 279 printf("Ignoring unhandled command 0x%x for Id %d\n", 280 atio.cdb_io.cdb_bytes[0], atio.init_id); 281 282 ioc_istate.initiator_id = atio.init_id; 283 if (ioctl(targfd, TARGIOCGETISTATE, &ioc_istate) == -1) { 284 perror("TARGIOCGETISTATE"); 285 exit(EX_SOFTWARE); 286 } 287 288 /* Send back Illegal Command code status */ 289 ioc_istate.istate.pending_ca |= CA_CMD_SENSE; 290 sense = &ioc_istate.istate.sense_data; 291 bzero(sense, sizeof(*sense)); 292 sense->error_code = SSD_CURRENT_ERROR; 293 sense->flags = SSD_KEY_ILLEGAL_REQUEST; 294 sense->add_sense_code = 0x20; 295 sense->add_sense_code_qual = 0x00; 296 sense->extra_len = offsetof(struct scsi_sense_data, fru) 297 - offsetof(struct scsi_sense_data, extra_len); 298 299 if (ioctl(targfd, TARGIOCSETISTATE, &ioc_istate) == -1) { 300 perror("TARGIOCSETISTATE"); 301 exit(EX_SOFTWARE); 302 } 303 304 bzero(&ccb, sizeof(ccb)); 305 cam_fill_ctio(&ccb.csio, /*retries*/2, 306 /*cbfcnp*/NULL, 307 /*flags*/CAM_DIR_NONE 308 | (atio.ccb_h.flags & CAM_TAG_ACTION_VALID) 309 | CAM_SEND_STATUS, 310 /*tag_action*/MSG_SIMPLE_Q_TAG, 311 atio.tag_id, 312 atio.init_id, 313 SCSI_STATUS_CHECK_COND, 314 /*data_ptr*/NULL, 315 /*dxfer_len*/0, 316 /*timeout*/5 * 1000); 317 if (ioctl(targfd, TARGIOCCOMMAND, &ccb) == -1) { 318 perror("TARGIOCCOMMAND"); 319 exit(EX_SOFTWARE); 320 } 321 322 } 323 324 if (ioctl(targfd, TARGIOCCLEAREXCEPTION, &exceptions) == -1) { 325 perror("TARGIOCCLEAREXCEPTION"); 326 exit(EX_SOFTWARE); 327 } 328 } 329 330 static void 331 quit_handler(int signum) 332 { 333 quit = 1; 334 } 335 336 static void 337 usage() 338 { 339 340 (void)fprintf(stderr, 341 "usage: %-16s [-o output_file] [-i input_file] -p path -t target -l lun\n", 342 appname); 343 344 exit(EX_USAGE); 345 } 346 347