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