scsi_target.c revision 41643
1132720Skan/*
2132720Skan * Sample program to attach to the "targ" processor target, target mode
3169691Skan * peripheral driver and push or receive data.
4169691Skan *
5132720Skan * Copyright (c) 1998 Justin T. Gibbs.
6132720Skan * All rights reserved.
7132720Skan *
8132720Skan * Redistribution and use in source and binary forms, with or without
9132720Skan * modification, are permitted provided that the following conditions
10132720Skan * are met:
11132720Skan * 1. Redistributions of source code must retain the above copyright
12132720Skan *    notice, this list of conditions, and the following disclaimer,
13132720Skan *    without modification, immediately at the beginning of the file.
14132720Skan * 2. The name of the author may not be used to endorse or promote products
15132720Skan *    derived from this software without specific prior written permission.
16132720Skan *
17132720Skan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18132720Skan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19169691Skan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20132720Skan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
21132720Skan * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22132720Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23132720Skan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24132720Skan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25132720Skan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26132720Skan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27132720Skan * SUCH DAMAGE.
28132720Skan *
29132720Skan *      $Id: scsi_target.c,v 1.1 1998/09/15 06:46:32 gibbs Exp $
30132720Skan */
31132720Skan
32132720Skan#include <sys/types.h>
33132720Skan
34132720Skan#include <fcntl.h>
35132720Skan#include <poll.h>
36132720Skan#include <stddef.h>
37132720Skan#include <stdio.h>
38132720Skan#include <stdlib.h>
39132720Skan#include <sysexits.h>
40132720Skan#include <unistd.h>
41132720Skan
42132720Skan#include <cam/scsi/scsi_all.h>
43132720Skan#include <cam/scsi/scsi_message.h>
44132720Skan#include <cam/scsi/scsi_targetio.h>
45132720Skan
46132720Skanchar  *appname;
47169691Skanint    ifd;
48132720Skanchar  *ifilename;
49132720Skanint    ofd;
50132720Skanchar  *ofilename;
51132720Skansize_t bufsize = 64 * 1024;
52146897Skanvoid  *buf;
53132720Skanchar  *targdevname;
54132720Skanint    targfd;
55169691Skan
56169691Skanstatic void pump_events();
57132720Skanstatic void handle_exception();
58169691Skanstatic void usage();
59169691Skan
60169691Skanint
61169691Skanmain(int argc, char *argv[])
62169691Skan{
63132720Skan	int  ch;
64169691Skan
65169691Skan	appname = *argv;
66132720Skan	while ((ch = getopt(argc, argv, "i:o:")) != -1) {
67132720Skan		switch(ch) {
68132720Skan		case 'i':
69132720Skan			if ((ifd = open(optarg, O_RDONLY)) == -1) {
70132720Skan				perror(optarg);
71132720Skan				exit(EX_NOINPUT);
72132720Skan			}
73132720Skan			ifilename = optarg;
74132720Skan			break;
75132720Skan		case 'o':
76132720Skan			if ((ofd = open(optarg,
77132720Skan					O_WRONLY|O_CREAT), 0600) == -1) {
78132720Skan				perror(optarg);
79132720Skan				exit(EX_CANTCREAT);
80132720Skan			}
81146897Skan			ofilename = optarg;
82132720Skan			break;
83132720Skan		case '?':
84132720Skan		default:
85132720Skan			usage();
86132720Skan			/* NOTREACHED */
87169691Skan		}
88132720Skan	}
89132720Skan	argc -= optind;
90132720Skan	argv += optind;
91132720Skan
92132720Skan	if (argc != 1) {
93132720Skan		fprintf(stderr, "%s: No target device specifiled\n", appname);
94132720Skan		usage();
95132720Skan		/* NOTREACHED */
96132720Skan	}
97132720Skan
98132720Skan	targdevname = *argv;
99132720Skan	if ((targfd = open(targdevname, O_RDWR)) == -1) {
100132720Skan		perror(targdevname);
101132720Skan		exit(EX_NOINPUT);
102132720Skan	}
103132720Skan
104132720Skan	buf = malloc(bufsize);
105132720Skan
106132720Skan	if (buf == NULL) {
107132720Skan		fprintf(stderr, "%s: Could not malloc I/O buffer", appname);
108132720Skan		exit(EX_OSERR);
109169691Skan	}
110132720Skan
111132720Skan	pump_events();
112132720Skan
113132720Skan	return (0);
114132720Skan}
115132720Skan
116132720Skanstatic void
117132720Skanpump_events()
118132720Skan{
119132720Skan	struct pollfd targpoll;
120132720Skan
121132720Skan	targpoll.fd = targfd;
122132720Skan	targpoll.events = POLLRDNORM|POLLWRNORM;
123132720Skan
124169691Skan	while (1) {
125132720Skan		int retval;
126146897Skan
127132720Skan		retval = poll(&targpoll, 1, INFTIM);
128132720Skan
129132720Skan		if (retval == -1) {
130132720Skan			perror("Poll Failed");
131132720Skan			exit(EX_SOFTWARE);
132132720Skan		}
133132720Skan
134132720Skan		if (retval == 0) {
135132720Skan			perror("Poll returned 0 although timeout infinite???");
136132720Skan			exit(EX_SOFTWARE);
137132720Skan		}
138132720Skan
139132720Skan		if (retval > 1) {
140132720Skan			perror("Poll returned more fds ready than allocated");
141132720Skan			exit(EX_SOFTWARE);
142132720Skan		}
143132720Skan
144132720Skan		/* Process events */
145132720Skan		if ((targpoll.revents & POLLERR) != 0) {
146132720Skan			handle_exception();
147132720Skan		}
148132720Skan
149132720Skan		if ((targpoll.revents & POLLRDNORM) != 0) {
150132720Skan			retval = read(targfd, buf, bufsize);
151132720Skan
152132720Skan			if (retval == -1) {
153132720Skan				perror("Read from targ failed");
154132720Skan			} else {
155132720Skan				retval = write(ofd, buf, retval);
156132720Skan				if (retval == -1) {
157132720Skan					perror("Write to file failed");
158132720Skan				}
159132720Skan			}
160132720Skan		}
161132720Skan
162132720Skan		if ((targpoll.revents & POLLWRNORM) != 0) {
163132720Skan			int amount_read;
164132720Skan
165132720Skan			retval = read(ifd, buf, bufsize);
166132720Skan			if (retval == -1) {
167132720Skan				perror("Read from file failed");
168132720Skan				exit(EX_SOFTWARE);
169132720Skan			}
170132720Skan
171132720Skan			amount_read = retval;
172132720Skan			retval = write(targfd, buf, retval);
173132720Skan			if (retval == -1) {
174132720Skan				perror("Write to targ failed");
175132720Skan				retval = 0;
176132720Skan			}
177132720Skan
178132720Skan			/* Backup in our input stream on short writes */
179132720Skan			if (retval != amount_read)
180132720Skan				lseek(ifd, retval - amount_read, SEEK_CUR);
181132720Skan		}
182132720Skan	}
183132720Skan}
184132720Skan
185132720Skanstatic void
186132720Skanhandle_exception()
187132720Skan{
188132720Skan	targ_exception exceptions;
189132720Skan
190132720Skan	if (ioctl(targfd, TARGIOCFETCHEXCEPTION, &exceptions) == -1) {
191132720Skan		perror("TARGIOCFETCHEXCEPTION");
192132720Skan		exit(EX_SOFTWARE);
193132720Skan	}
194132720Skan
195132720Skan	if ((exceptions & TARG_EXCEPT_DEVICE_INVALID) != 0) {
196132720Skan		/* Device went away.  Nothing more to do. */
197132720Skan		exit(0);
198169691Skan	}
199132720Skan
200169691Skan	if ((exceptions & TARG_EXCEPT_UNKNOWN_ATIO) != 0) {
201169691Skan		struct ccb_accept_tio atio;
202169691Skan		struct ioc_initiator_state ioc_istate;
203169691Skan		struct scsi_sense_data *sense;
204169691Skan		union  ccb ccb;
205169691Skan
206169691Skan		if (ioctl(targfd, TARGIOCFETCHATIO, &atio) == -1) {
207132720Skan			perror("TARGIOCFETCHATIO");
208169691Skan			exit(EX_SOFTWARE);
209169691Skan		}
210169691Skan
211169691Skan		printf("Ignoring unhandled command 0x%x for Id %d\n",
212169691Skan		       atio.cdb_io.cdb_bytes[0], atio.init_id);
213132720Skan
214169691Skan		ioc_istate.initiator_id = atio.init_id;
215169691Skan		if (ioctl(targfd, TARGIOCGETISTATE, &ioc_istate) == -1) {
216169691Skan			perror("TARGIOCGETISTATE");
217169691Skan			exit(EX_SOFTWARE);
218169691Skan		}
219169691Skan
220169691Skan		/* Send back Illegal Command code status */
221169691Skan		ioc_istate.istate.pending_ca |= CA_CMD_SENSE;
222169691Skan		sense = &ioc_istate.istate.sense_data;
223169691Skan		bzero(sense, sizeof(*sense));
224169691Skan		sense->error_code = SSD_CURRENT_ERROR;
225132720Skan		sense->flags = SSD_KEY_ILLEGAL_REQUEST;
226132720Skan		sense->add_sense_code = 0x20;
227169691Skan		sense->add_sense_code_qual = 0x00;
228169691Skan		sense->extra_len = offsetof(struct scsi_sense_data, fru)
229132720Skan				 - offsetof(struct scsi_sense_data, extra_len);
230169691Skan
231169691Skan		if (ioctl(targfd, TARGIOCSETISTATE, &ioc_istate) == -1) {
232132720Skan			perror("TARGIOCSETISTATE");
233132720Skan			exit(EX_SOFTWARE);
234132720Skan		}
235132720Skan
236132720Skan		bzero(&ccb, sizeof(ccb));
237132720Skan		cam_fill_ctio(&ccb.csio, /*retries*/2,
238132720Skan			      /*cbfcnp*/NULL,
239132720Skan			      /*flags*/CAM_DIR_NONE
240132720Skan			     | (atio.ccb_h.flags & CAM_TAG_ACTION_VALID)
241169691Skan			     | CAM_SEND_STATUS,
242132720Skan                              /*tag_action*/MSG_SIMPLE_Q_TAG,
243132720Skan			      atio.tag_id,
244132720Skan			      atio.init_id,
245132720Skan			      SCSI_STATUS_CHECK_COND,
246132720Skan			      /*data_ptr*/NULL,
247132720Skan			      /*dxfer_len*/0,
248132720Skan			      /*timeout*/5 * 1000);
249132720Skan		if (ioctl(targfd, TARGIOCCOMMAND, &ccb) == -1) {
250132720Skan			perror("TARGIOCCOMMAND");
251169691Skan			exit(EX_SOFTWARE);
252132720Skan		}
253132720Skan
254132720Skan	}
255132720Skan
256132720Skan	if (ioctl(targfd, TARGIOCCLEAREXCEPTION, &exceptions) == -1) {
257132720Skan		perror("TARGIOCCLEAREXCEPTION");
258169691Skan		exit(EX_SOFTWARE);
259169691Skan	}
260132720Skan}
261
262static void
263usage()
264{
265
266	(void)fprintf(stderr,
267"usage: %-16s [-o output_file] [-i input_file] /dev/targ?\n", appname);
268
269	exit(EX_USAGE);
270}
271
272