xref: /freebsd/share/examples/scsi_target/scsi_target.c (revision 97188b54ce326ce175148e156aea2cdee7c3fbe9)
19875eecfSJustin T. Gibbs /*
29875eecfSJustin T. Gibbs  * Sample program to attach to the "targ" processor target, target mode
39875eecfSJustin T. Gibbs  * peripheral driver and push or receive data.
49875eecfSJustin T. Gibbs  *
59875eecfSJustin T. Gibbs  * Copyright (c) 1998 Justin T. Gibbs.
69875eecfSJustin T. Gibbs  * All rights reserved.
79875eecfSJustin T. Gibbs  *
89875eecfSJustin T. Gibbs  * Redistribution and use in source and binary forms, with or without
99875eecfSJustin T. Gibbs  * modification, are permitted provided that the following conditions
109875eecfSJustin T. Gibbs  * are met:
119875eecfSJustin T. Gibbs  * 1. Redistributions of source code must retain the above copyright
129875eecfSJustin T. Gibbs  *    notice, this list of conditions, and the following disclaimer,
139875eecfSJustin T. Gibbs  *    without modification, immediately at the beginning of the file.
149875eecfSJustin T. Gibbs  * 2. The name of the author may not be used to endorse or promote products
159875eecfSJustin T. Gibbs  *    derived from this software without specific prior written permission.
169875eecfSJustin T. Gibbs  *
179875eecfSJustin T. Gibbs  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
189875eecfSJustin T. Gibbs  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
199875eecfSJustin T. Gibbs  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
209875eecfSJustin T. Gibbs  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
219875eecfSJustin T. Gibbs  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
229875eecfSJustin T. Gibbs  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
239875eecfSJustin T. Gibbs  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
249875eecfSJustin T. Gibbs  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
259875eecfSJustin T. Gibbs  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
269875eecfSJustin T. Gibbs  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
279875eecfSJustin T. Gibbs  * SUCH DAMAGE.
289875eecfSJustin T. Gibbs  *
297f3dea24SPeter Wemm  * $FreeBSD$
309875eecfSJustin T. Gibbs  */
319875eecfSJustin T. Gibbs 
329875eecfSJustin T. Gibbs #include <sys/types.h>
339875eecfSJustin T. Gibbs 
34b3fae35cSJustin T. Gibbs #include <errno.h>
359875eecfSJustin T. Gibbs #include <fcntl.h>
369875eecfSJustin T. Gibbs #include <poll.h>
37b3fae35cSJustin T. Gibbs #include <signal.h>
389875eecfSJustin T. Gibbs #include <stddef.h>
399875eecfSJustin T. Gibbs #include <stdio.h>
409875eecfSJustin T. Gibbs #include <stdlib.h>
419875eecfSJustin T. Gibbs #include <sysexits.h>
429875eecfSJustin T. Gibbs #include <unistd.h>
439875eecfSJustin T. Gibbs 
449875eecfSJustin T. Gibbs #include <cam/scsi/scsi_all.h>
459875eecfSJustin T. Gibbs #include <cam/scsi/scsi_message.h>
469875eecfSJustin T. Gibbs #include <cam/scsi/scsi_targetio.h>
479875eecfSJustin T. Gibbs 
489875eecfSJustin T. Gibbs char	*appname;
499875eecfSJustin T. Gibbs int	 ifd;
509875eecfSJustin T. Gibbs char	*ifilename;
519875eecfSJustin T. Gibbs int	 ofd;
529875eecfSJustin T. Gibbs char	*ofilename;
539875eecfSJustin T. Gibbs size_t	 bufsize = 64 * 1024;
549875eecfSJustin T. Gibbs void	*buf;
55b3fae35cSJustin T. Gibbs char	 targdevname[80];
56b3fae35cSJustin T. Gibbs int	 targctlfd;
579875eecfSJustin T. Gibbs int	 targfd;
58b3fae35cSJustin T. Gibbs int	 quit;
5997188b54SMatt Jacob int      debug = 0;
60b3fae35cSJustin T. Gibbs struct	 ioc_alloc_unit alloc_unit = {
61b3fae35cSJustin T. Gibbs 	CAM_BUS_WILDCARD,
62b3fae35cSJustin T. Gibbs 	CAM_TARGET_WILDCARD,
63b3fae35cSJustin T. Gibbs 	CAM_LUN_WILDCARD
64b3fae35cSJustin T. Gibbs };
659875eecfSJustin T. Gibbs 
669875eecfSJustin T. Gibbs static void pump_events();
6787609397SJustin T. Gibbs static void cleanup();
689875eecfSJustin T. Gibbs static void handle_exception();
69b3fae35cSJustin T. Gibbs static void quit_handler();
709875eecfSJustin T. Gibbs static void usage();
719875eecfSJustin T. Gibbs 
729875eecfSJustin T. Gibbs int
739875eecfSJustin T. Gibbs main(int argc, char *argv[])
749875eecfSJustin T. Gibbs {
759875eecfSJustin T. Gibbs 	int  ch;
769875eecfSJustin T. Gibbs 
779875eecfSJustin T. Gibbs 	appname = *argv;
7897188b54SMatt Jacob 	while ((ch = getopt(argc, argv, "i:o:p:t:l:d")) != -1) {
799875eecfSJustin T. Gibbs 		switch(ch) {
809875eecfSJustin T. Gibbs 		case 'i':
819875eecfSJustin T. Gibbs 			if ((ifd = open(optarg, O_RDONLY)) == -1) {
829875eecfSJustin T. Gibbs 				perror(optarg);
839875eecfSJustin T. Gibbs 				exit(EX_NOINPUT);
849875eecfSJustin T. Gibbs 			}
859875eecfSJustin T. Gibbs 			ifilename = optarg;
869875eecfSJustin T. Gibbs 			break;
879875eecfSJustin T. Gibbs 		case 'o':
889875eecfSJustin T. Gibbs 			if ((ofd = open(optarg,
899875eecfSJustin T. Gibbs 					O_WRONLY|O_CREAT), 0600) == -1) {
909875eecfSJustin T. Gibbs 				perror(optarg);
919875eecfSJustin T. Gibbs 				exit(EX_CANTCREAT);
929875eecfSJustin T. Gibbs 			}
939875eecfSJustin T. Gibbs 			ofilename = optarg;
949875eecfSJustin T. Gibbs 			break;
95b3fae35cSJustin T. Gibbs 		case 'p':
96b3fae35cSJustin T. Gibbs 			alloc_unit.path_id = atoi(optarg);
97b3fae35cSJustin T. Gibbs 			break;
98b3fae35cSJustin T. Gibbs 		case 't':
99b3fae35cSJustin T. Gibbs 			alloc_unit.target_id = atoi(optarg);
100b3fae35cSJustin T. Gibbs 			break;
101b3fae35cSJustin T. Gibbs 		case 'l':
102b3fae35cSJustin T. Gibbs 			alloc_unit.lun_id = atoi(optarg);
103b3fae35cSJustin T. Gibbs 			break;
10497188b54SMatt Jacob 		case 'd':
10597188b54SMatt Jacob 			debug++;
10697188b54SMatt Jacob 			break;
1079875eecfSJustin T. Gibbs 		case '?':
1089875eecfSJustin T. Gibbs 		default:
1099875eecfSJustin T. Gibbs 			usage();
1109875eecfSJustin T. Gibbs 			/* NOTREACHED */
1119875eecfSJustin T. Gibbs 		}
1129875eecfSJustin T. Gibbs 	}
1139875eecfSJustin T. Gibbs 	argc -= optind;
1149875eecfSJustin T. Gibbs 	argv += optind;
1159875eecfSJustin T. Gibbs 
116b3fae35cSJustin T. Gibbs 	if (alloc_unit.path_id == CAM_BUS_WILDCARD
117b3fae35cSJustin T. Gibbs 	 || alloc_unit.target_id == CAM_TARGET_WILDCARD
118b3fae35cSJustin T. Gibbs 	 || alloc_unit.lun_id == CAM_LUN_WILDCARD) {
119b3fae35cSJustin T. Gibbs 		fprintf(stderr, "%s: Incomplete device path specifiled\n",
120b3fae35cSJustin T. Gibbs 			appname);
1219875eecfSJustin T. Gibbs 		usage();
1229875eecfSJustin T. Gibbs 		/* NOTREACHED */
1239875eecfSJustin T. Gibbs 	}
1249875eecfSJustin T. Gibbs 
125b3fae35cSJustin T. Gibbs 	if (argc != 0) {
126b3fae35cSJustin T. Gibbs 		fprintf(stderr, "%s: Too many arguments\n", appname);
127b3fae35cSJustin T. Gibbs 		usage();
128b3fae35cSJustin T. Gibbs 		/* NOTREACHED */
129b3fae35cSJustin T. Gibbs 	}
130b3fae35cSJustin T. Gibbs 
131b3fae35cSJustin T. Gibbs 	/* Allocate a new instance */
132b3fae35cSJustin T. Gibbs 	if ((targctlfd = open("/dev/targ.ctl", O_RDWR)) == -1) {
133b3fae35cSJustin T. Gibbs 		perror("/dev/targ.ctl");
134b3fae35cSJustin T. Gibbs 		exit(EX_UNAVAILABLE);
135b3fae35cSJustin T. Gibbs 	}
136b3fae35cSJustin T. Gibbs 
137b3fae35cSJustin T. Gibbs 	if (ioctl(targctlfd, TARGCTLIOALLOCUNIT, &alloc_unit) == -1) {
138b3fae35cSJustin T. Gibbs 		perror("TARGCTLIOALLOCUNIT");
139b3fae35cSJustin T. Gibbs 		exit(EX_SOFTWARE);
140b3fae35cSJustin T. Gibbs 	}
141b3fae35cSJustin T. Gibbs 
142b3fae35cSJustin T. Gibbs 	snprintf(targdevname, sizeof(targdevname), "/dev/targ%d",
143b3fae35cSJustin T. Gibbs 		 alloc_unit.unit);
144b3fae35cSJustin T. Gibbs 
1459875eecfSJustin T. Gibbs 	if ((targfd = open(targdevname, O_RDWR)) == -1) {
1469875eecfSJustin T. Gibbs 		perror(targdevname);
147b3fae35cSJustin T. Gibbs 		ioctl(targctlfd, TARGCTLIOFREEUNIT, &alloc_unit);
1489875eecfSJustin T. Gibbs 		exit(EX_NOINPUT);
1499875eecfSJustin T. Gibbs 	}
1509875eecfSJustin T. Gibbs 
15197188b54SMatt Jacob 	if (ioctl(targfd, TARGIODEBUG, &debug) == -1) {
15297188b54SMatt Jacob 		perror("TARGIODEBUG");
15397188b54SMatt Jacob 		exit(EX_SOFTWARE);
15497188b54SMatt Jacob 	}
15597188b54SMatt Jacob 
1569875eecfSJustin T. Gibbs 	buf = malloc(bufsize);
1579875eecfSJustin T. Gibbs 
1589875eecfSJustin T. Gibbs 	if (buf == NULL) {
1599875eecfSJustin T. Gibbs 		fprintf(stderr, "%s: Could not malloc I/O buffer", appname);
1609875eecfSJustin T. Gibbs 		exit(EX_OSERR);
1619875eecfSJustin T. Gibbs 	}
1629875eecfSJustin T. Gibbs 
163b3fae35cSJustin T. Gibbs 	signal(SIGHUP, quit_handler);
164b3fae35cSJustin T. Gibbs 	signal(SIGINT, quit_handler);
165b3fae35cSJustin T. Gibbs 	signal(SIGTERM, quit_handler);
166b3fae35cSJustin T. Gibbs 
16787609397SJustin T. Gibbs 	atexit(cleanup);
16887609397SJustin T. Gibbs 
1699875eecfSJustin T. Gibbs 	pump_events();
1709875eecfSJustin T. Gibbs 
17187609397SJustin T. Gibbs 	return (0);
17287609397SJustin T. Gibbs }
17387609397SJustin T. Gibbs 
17487609397SJustin T. Gibbs static void
17587609397SJustin T. Gibbs cleanup()
17687609397SJustin T. Gibbs {
177b3fae35cSJustin T. Gibbs 	close(targfd);
178b3fae35cSJustin T. Gibbs 
179b3fae35cSJustin T. Gibbs 	if (ioctl(targctlfd, TARGCTLIOFREEUNIT, &alloc_unit) == -1) {
180b3fae35cSJustin T. Gibbs 		perror("TARGCTLIOFREEUNIT");
181b3fae35cSJustin T. Gibbs 		exit(EX_SOFTWARE);
182b3fae35cSJustin T. Gibbs 	}
183b3fae35cSJustin T. Gibbs 
184b3fae35cSJustin T. Gibbs 	close(targctlfd);
1859875eecfSJustin T. Gibbs }
1869875eecfSJustin T. Gibbs 
1879875eecfSJustin T. Gibbs static void
1889875eecfSJustin T. Gibbs pump_events()
1899875eecfSJustin T. Gibbs {
1909875eecfSJustin T. Gibbs 	struct pollfd targpoll;
1919875eecfSJustin T. Gibbs 
1929875eecfSJustin T. Gibbs 	targpoll.fd = targfd;
1939875eecfSJustin T. Gibbs 	targpoll.events = POLLRDNORM|POLLWRNORM;
1949875eecfSJustin T. Gibbs 
195b3fae35cSJustin T. Gibbs 	while (quit == 0) {
1969875eecfSJustin T. Gibbs 		int retval;
1979875eecfSJustin T. Gibbs 
1989875eecfSJustin T. Gibbs 		retval = poll(&targpoll, 1, INFTIM);
1999875eecfSJustin T. Gibbs 
2009875eecfSJustin T. Gibbs 		if (retval == -1) {
201b3fae35cSJustin T. Gibbs 			if (errno == EINTR)
202b3fae35cSJustin T. Gibbs 				continue;
2039875eecfSJustin T. Gibbs 			perror("Poll Failed");
2049875eecfSJustin T. Gibbs 			exit(EX_SOFTWARE);
2059875eecfSJustin T. Gibbs 		}
2069875eecfSJustin T. Gibbs 
2079875eecfSJustin T. Gibbs 		if (retval == 0) {
2089875eecfSJustin T. Gibbs 			perror("Poll returned 0 although timeout infinite???");
2099875eecfSJustin T. Gibbs 			exit(EX_SOFTWARE);
2109875eecfSJustin T. Gibbs 		}
2119875eecfSJustin T. Gibbs 
2129875eecfSJustin T. Gibbs 		if (retval > 1) {
2139875eecfSJustin T. Gibbs 			perror("Poll returned more fds ready than allocated");
2149875eecfSJustin T. Gibbs 			exit(EX_SOFTWARE);
2159875eecfSJustin T. Gibbs 		}
2169875eecfSJustin T. Gibbs 
2179875eecfSJustin T. Gibbs 		/* Process events */
2189875eecfSJustin T. Gibbs 		if ((targpoll.revents & POLLERR) != 0) {
2199875eecfSJustin T. Gibbs 			handle_exception();
2209875eecfSJustin T. Gibbs 		}
2219875eecfSJustin T. Gibbs 
2229875eecfSJustin T. Gibbs 		if ((targpoll.revents & POLLRDNORM) != 0) {
2239875eecfSJustin T. Gibbs 			retval = read(targfd, buf, bufsize);
2249875eecfSJustin T. Gibbs 
2259875eecfSJustin T. Gibbs 			if (retval == -1) {
2269875eecfSJustin T. Gibbs 				perror("Read from targ failed");
22787609397SJustin T. Gibbs 				/* Go look for exceptions */
22887609397SJustin T. Gibbs 				continue;
2299875eecfSJustin T. Gibbs 			} else {
2309875eecfSJustin T. Gibbs 				retval = write(ofd, buf, retval);
2319875eecfSJustin T. Gibbs 				if (retval == -1) {
2329875eecfSJustin T. Gibbs 					perror("Write to file failed");
2339875eecfSJustin T. Gibbs 				}
2349875eecfSJustin T. Gibbs 			}
2359875eecfSJustin T. Gibbs 		}
2369875eecfSJustin T. Gibbs 
2379875eecfSJustin T. Gibbs 		if ((targpoll.revents & POLLWRNORM) != 0) {
2389875eecfSJustin T. Gibbs 			int amount_read;
2399875eecfSJustin T. Gibbs 
2409875eecfSJustin T. Gibbs 			retval = read(ifd, buf, bufsize);
2419875eecfSJustin T. Gibbs 			if (retval == -1) {
2429875eecfSJustin T. Gibbs 				perror("Read from file failed");
2439875eecfSJustin T. Gibbs 				exit(EX_SOFTWARE);
2449875eecfSJustin T. Gibbs 			}
2459875eecfSJustin T. Gibbs 
2469875eecfSJustin T. Gibbs 			amount_read = retval;
2479875eecfSJustin T. Gibbs 			retval = write(targfd, buf, retval);
2489875eecfSJustin T. Gibbs 			if (retval == -1) {
2499875eecfSJustin T. Gibbs 				perror("Write to targ failed");
2509875eecfSJustin T. Gibbs 				retval = 0;
2519875eecfSJustin T. Gibbs 			}
2529875eecfSJustin T. Gibbs 
2539875eecfSJustin T. Gibbs 			/* Backup in our input stream on short writes */
2549875eecfSJustin T. Gibbs 			if (retval != amount_read)
2559875eecfSJustin T. Gibbs 				lseek(ifd, retval - amount_read, SEEK_CUR);
2569875eecfSJustin T. Gibbs 		}
2579875eecfSJustin T. Gibbs 	}
2589875eecfSJustin T. Gibbs }
2599875eecfSJustin T. Gibbs 
2609875eecfSJustin T. Gibbs static void
2619875eecfSJustin T. Gibbs handle_exception()
2629875eecfSJustin T. Gibbs {
2639875eecfSJustin T. Gibbs 	targ_exception exceptions;
2649875eecfSJustin T. Gibbs 
2659875eecfSJustin T. Gibbs 	if (ioctl(targfd, TARGIOCFETCHEXCEPTION, &exceptions) == -1) {
2669875eecfSJustin T. Gibbs 		perror("TARGIOCFETCHEXCEPTION");
2679875eecfSJustin T. Gibbs 		exit(EX_SOFTWARE);
2689875eecfSJustin T. Gibbs 	}
2699875eecfSJustin T. Gibbs 
27087609397SJustin T. Gibbs 	printf("Saw exceptions %x\n", exceptions);
2719875eecfSJustin T. Gibbs 	if ((exceptions & TARG_EXCEPT_DEVICE_INVALID) != 0) {
2729875eecfSJustin T. Gibbs 		/* Device went away.  Nothing more to do. */
27387609397SJustin T. Gibbs 		printf("Device went away\n");
2749875eecfSJustin T. Gibbs 		exit(0);
2759875eecfSJustin T. Gibbs 	}
2769875eecfSJustin T. Gibbs 
2779875eecfSJustin T. Gibbs 	if ((exceptions & TARG_EXCEPT_UNKNOWN_ATIO) != 0) {
2789875eecfSJustin T. Gibbs 		struct ccb_accept_tio atio;
2799875eecfSJustin T. Gibbs 		struct ioc_initiator_state ioc_istate;
2809875eecfSJustin T. Gibbs 		struct scsi_sense_data *sense;
2819875eecfSJustin T. Gibbs 		union  ccb ccb;
2829875eecfSJustin T. Gibbs 
2839875eecfSJustin T. Gibbs 		if (ioctl(targfd, TARGIOCFETCHATIO, &atio) == -1) {
2849875eecfSJustin T. Gibbs 			perror("TARGIOCFETCHATIO");
2859875eecfSJustin T. Gibbs 			exit(EX_SOFTWARE);
2869875eecfSJustin T. Gibbs 		}
2879875eecfSJustin T. Gibbs 
2889875eecfSJustin T. Gibbs 		printf("Ignoring unhandled command 0x%x for Id %d\n",
2899875eecfSJustin T. Gibbs 		       atio.cdb_io.cdb_bytes[0], atio.init_id);
2909875eecfSJustin T. Gibbs 
2919875eecfSJustin T. Gibbs 		ioc_istate.initiator_id = atio.init_id;
2929875eecfSJustin T. Gibbs 		if (ioctl(targfd, TARGIOCGETISTATE, &ioc_istate) == -1) {
2939875eecfSJustin T. Gibbs 			perror("TARGIOCGETISTATE");
2949875eecfSJustin T. Gibbs 			exit(EX_SOFTWARE);
2959875eecfSJustin T. Gibbs 		}
2969875eecfSJustin T. Gibbs 
2979875eecfSJustin T. Gibbs 		/* Send back Illegal Command code status */
2989875eecfSJustin T. Gibbs 		ioc_istate.istate.pending_ca |= CA_CMD_SENSE;
2999875eecfSJustin T. Gibbs 		sense = &ioc_istate.istate.sense_data;
3009875eecfSJustin T. Gibbs 		bzero(sense, sizeof(*sense));
3019875eecfSJustin T. Gibbs 		sense->error_code = SSD_CURRENT_ERROR;
3029875eecfSJustin T. Gibbs 		sense->flags = SSD_KEY_ILLEGAL_REQUEST;
3039875eecfSJustin T. Gibbs 		sense->add_sense_code = 0x20;
3049875eecfSJustin T. Gibbs 		sense->add_sense_code_qual = 0x00;
3059875eecfSJustin T. Gibbs 		sense->extra_len = offsetof(struct scsi_sense_data, fru)
3069875eecfSJustin T. Gibbs 				 - offsetof(struct scsi_sense_data, extra_len);
3079875eecfSJustin T. Gibbs 
3089875eecfSJustin T. Gibbs 		if (ioctl(targfd, TARGIOCSETISTATE, &ioc_istate) == -1) {
3099875eecfSJustin T. Gibbs 			perror("TARGIOCSETISTATE");
3109875eecfSJustin T. Gibbs 			exit(EX_SOFTWARE);
3119875eecfSJustin T. Gibbs 		}
3129875eecfSJustin T. Gibbs 
31397188b54SMatt Jacob 		/* Clear the exception so the kernel will take our response */
31497188b54SMatt Jacob 		if (ioctl(targfd, TARGIOCCLEAREXCEPTION, &exceptions) == -1) {
31597188b54SMatt Jacob 			perror("TARGIOCCLEAREXCEPTION");
31697188b54SMatt Jacob 			exit(EX_SOFTWARE);
31797188b54SMatt Jacob 		}
31897188b54SMatt Jacob 
3199875eecfSJustin T. Gibbs 		bzero(&ccb, sizeof(ccb));
3209875eecfSJustin T. Gibbs 		cam_fill_ctio(&ccb.csio, /*retries*/2,
3219875eecfSJustin T. Gibbs 			      /*cbfcnp*/NULL,
3229875eecfSJustin T. Gibbs 			      /*flags*/CAM_DIR_NONE
3239875eecfSJustin T. Gibbs 			     | (atio.ccb_h.flags & CAM_TAG_ACTION_VALID)
3249875eecfSJustin T. Gibbs 			     | CAM_SEND_STATUS,
3259875eecfSJustin T. Gibbs                               /*tag_action*/MSG_SIMPLE_Q_TAG,
3269875eecfSJustin T. Gibbs 			      atio.tag_id,
3279875eecfSJustin T. Gibbs 			      atio.init_id,
3289875eecfSJustin T. Gibbs 			      SCSI_STATUS_CHECK_COND,
3299875eecfSJustin T. Gibbs 			      /*data_ptr*/NULL,
3309875eecfSJustin T. Gibbs 			      /*dxfer_len*/0,
3319875eecfSJustin T. Gibbs 			      /*timeout*/5 * 1000);
33297188b54SMatt Jacob 
3339875eecfSJustin T. Gibbs 		if (ioctl(targfd, TARGIOCCOMMAND, &ccb) == -1) {
3349875eecfSJustin T. Gibbs 			perror("TARGIOCCOMMAND");
3359875eecfSJustin T. Gibbs 			exit(EX_SOFTWARE);
3369875eecfSJustin T. Gibbs 		}
3379875eecfSJustin T. Gibbs 
33897188b54SMatt Jacob 	} else {
3399875eecfSJustin T. Gibbs 		if (ioctl(targfd, TARGIOCCLEAREXCEPTION, &exceptions) == -1) {
3409875eecfSJustin T. Gibbs 			perror("TARGIOCCLEAREXCEPTION");
3419875eecfSJustin T. Gibbs 			exit(EX_SOFTWARE);
3429875eecfSJustin T. Gibbs 		}
3439875eecfSJustin T. Gibbs 	}
3449875eecfSJustin T. Gibbs 
34597188b54SMatt Jacob }
34697188b54SMatt Jacob 
3479875eecfSJustin T. Gibbs static void
348b3fae35cSJustin T. Gibbs quit_handler(int signum)
349b3fae35cSJustin T. Gibbs {
350b3fae35cSJustin T. Gibbs 	quit = 1;
351b3fae35cSJustin T. Gibbs }
352b3fae35cSJustin T. Gibbs 
353b3fae35cSJustin T. Gibbs static void
3549875eecfSJustin T. Gibbs usage()
3559875eecfSJustin T. Gibbs {
3569875eecfSJustin T. Gibbs 
3579875eecfSJustin T. Gibbs 	(void)fprintf(stderr,
35897188b54SMatt Jacob "usage: %-16s [ -d ] [-o output_file] [-i input_file] -p path -t target -l lun\n",
359b3fae35cSJustin T. Gibbs 		      appname);
3609875eecfSJustin T. Gibbs 
3619875eecfSJustin T. Gibbs 	exit(EX_USAGE);
3629875eecfSJustin T. Gibbs }
3639875eecfSJustin T. Gibbs 
364