xref: /freebsd/contrib/netbsd-tests/dev/scsipi/libscsitest/scsitest.c (revision 9268022b74279434ed6300244e3f977e56a8ceb5)
1*57718be8SEnji Cooper /*	$NetBSD: scsitest.c,v 1.2 2014/04/25 00:24:39 pooka Exp $	*/
2*57718be8SEnji Cooper 
3*57718be8SEnji Cooper /*
4*57718be8SEnji Cooper  * Copyright (c) 2010 Antti Kantee.  All Rights Reserved.
5*57718be8SEnji Cooper  *
6*57718be8SEnji Cooper  * Redistribution and use in source and binary forms, with or without
7*57718be8SEnji Cooper  * modification, are permitted provided that the following conditions
8*57718be8SEnji Cooper  * are met:
9*57718be8SEnji Cooper  * 1. Redistributions of source code must retain the above copyright
10*57718be8SEnji Cooper  *    notice, this list of conditions and the following disclaimer.
11*57718be8SEnji Cooper  * 2. Redistributions in binary form must reproduce the above copyright
12*57718be8SEnji Cooper  *    notice, this list of conditions and the following disclaimer in the
13*57718be8SEnji Cooper  *    documentation and/or other materials provided with the distribution.
14*57718be8SEnji Cooper  *
15*57718be8SEnji Cooper  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16*57718be8SEnji Cooper  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17*57718be8SEnji Cooper  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18*57718be8SEnji Cooper  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19*57718be8SEnji Cooper  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20*57718be8SEnji Cooper  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21*57718be8SEnji Cooper  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22*57718be8SEnji Cooper  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23*57718be8SEnji Cooper  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24*57718be8SEnji Cooper  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25*57718be8SEnji Cooper  * SUCH DAMAGE.
26*57718be8SEnji Cooper  */
27*57718be8SEnji Cooper 
28*57718be8SEnji Cooper /*
29*57718be8SEnji Cooper  * A SCSI target which is useful for debugging our scsipi driver stack.
30*57718be8SEnji Cooper  * Currently it pretends to be a single CD.
31*57718be8SEnji Cooper  *
32*57718be8SEnji Cooper  * Freely add the necessary features for your tests.  Just remember to
33*57718be8SEnji Cooper  * run the atf test suite to make sure you didn't cause regressions to
34*57718be8SEnji Cooper  * other tests.
35*57718be8SEnji Cooper  */
36*57718be8SEnji Cooper 
37*57718be8SEnji Cooper #include <sys/cdefs.h>
38*57718be8SEnji Cooper __KERNEL_RCSID(0, "$NetBSD: scsitest.c,v 1.2 2014/04/25 00:24:39 pooka Exp $");
39*57718be8SEnji Cooper 
40*57718be8SEnji Cooper #include <sys/param.h>
41*57718be8SEnji Cooper #include <sys/atomic.h>
42*57718be8SEnji Cooper #include <sys/buf.h>
43*57718be8SEnji Cooper #include <sys/device.h>
44*57718be8SEnji Cooper #include <sys/malloc.h>
45*57718be8SEnji Cooper #include <sys/fcntl.h>
46*57718be8SEnji Cooper 
47*57718be8SEnji Cooper #include <dev/scsipi/scsiconf.h>
48*57718be8SEnji Cooper #include <dev/scsipi/scsipiconf.h>
49*57718be8SEnji Cooper #include <dev/scsipi/scsi_disk.h>
50*57718be8SEnji Cooper #include <dev/scsipi/scsipi_cd.h>
51*57718be8SEnji Cooper #include <dev/scsipi/scsipi_all.h>
52*57718be8SEnji Cooper 
53*57718be8SEnji Cooper #include <rump/rumpuser.h>
54*57718be8SEnji Cooper 
55*57718be8SEnji Cooper #include "scsitest.h"
56*57718be8SEnji Cooper 
57*57718be8SEnji Cooper int	scsitest_match(device_t, cfdata_t, void *);
58*57718be8SEnji Cooper void	scsitest_attach(device_t, device_t, void *);
59*57718be8SEnji Cooper 
60*57718be8SEnji Cooper struct scsitest {
61*57718be8SEnji Cooper 	struct scsipi_channel sc_channel;
62*57718be8SEnji Cooper 	struct scsipi_adapter sc_adapter;
63*57718be8SEnji Cooper };
64*57718be8SEnji Cooper 
65*57718be8SEnji Cooper CFATTACH_DECL_NEW(scsitest, sizeof(struct scsitest), scsitest_match,
66*57718be8SEnji Cooper 	scsitest_attach, NULL, NULL);
67*57718be8SEnji Cooper 
68*57718be8SEnji Cooper /*
69*57718be8SEnji Cooper  * tosi.iso can be used to deliver CD requests to a host file with the
70*57718be8SEnji Cooper  * name in USE_TOSI_ISO (yes, it's extrasimplistic).
71*57718be8SEnji Cooper  */
72*57718be8SEnji Cooper //#define USE_TOSI_ISO
73*57718be8SEnji Cooper 
74*57718be8SEnji Cooper #define CDBLOCKSIZE 2048
75*57718be8SEnji Cooper static uint32_t mycdsize = 2048;
76*57718be8SEnji Cooper static int isofd;
77*57718be8SEnji Cooper 
78*57718be8SEnji Cooper #define MYCDISO "tosi.iso"
79*57718be8SEnji Cooper 
80*57718be8SEnji Cooper unsigned rump_scsitest_err[RUMP_SCSITEST_MAXERROR];
81*57718be8SEnji Cooper 
82*57718be8SEnji Cooper static void
sense_notready(struct scsipi_xfer * xs)83*57718be8SEnji Cooper sense_notready(struct scsipi_xfer *xs)
84*57718be8SEnji Cooper {
85*57718be8SEnji Cooper 	struct scsi_sense_data *sense = &xs->sense.scsi_sense;
86*57718be8SEnji Cooper 
87*57718be8SEnji Cooper 	xs->error = XS_SENSE;
88*57718be8SEnji Cooper 
89*57718be8SEnji Cooper 	sense->response_code = 0x70;
90*57718be8SEnji Cooper 	sense->flags = SKEY_NOT_READY;
91*57718be8SEnji Cooper 	sense->asc = 0x3A;
92*57718be8SEnji Cooper 	sense->ascq = 0x00;
93*57718be8SEnji Cooper 	sense->extra_len = 6;
94*57718be8SEnji Cooper }
95*57718be8SEnji Cooper 
96*57718be8SEnji Cooper /*
97*57718be8SEnji Cooper  * This is pretty much a CD target for now
98*57718be8SEnji Cooper  */
99*57718be8SEnji Cooper static void
scsitest_request(struct scsipi_channel * chan,scsipi_adapter_req_t req,void * arg)100*57718be8SEnji Cooper scsitest_request(struct scsipi_channel *chan,
101*57718be8SEnji Cooper 	scsipi_adapter_req_t req, void *arg)
102*57718be8SEnji Cooper {
103*57718be8SEnji Cooper 	struct scsipi_xfer *xs = arg;
104*57718be8SEnji Cooper 	struct scsipi_generic *cmd = xs->cmd;
105*57718be8SEnji Cooper #ifdef USE_TOSI_ISO
106*57718be8SEnji Cooper 	int error;
107*57718be8SEnji Cooper #endif
108*57718be8SEnji Cooper 
109*57718be8SEnji Cooper 	if (req != ADAPTER_REQ_RUN_XFER)
110*57718be8SEnji Cooper 		return;
111*57718be8SEnji Cooper 
112*57718be8SEnji Cooper 	//show_scsipi_xs(xs);
113*57718be8SEnji Cooper 
114*57718be8SEnji Cooper 	switch (cmd->opcode) {
115*57718be8SEnji Cooper 	case SCSI_TEST_UNIT_READY:
116*57718be8SEnji Cooper 		if (isofd == -1)
117*57718be8SEnji Cooper 			sense_notready(xs);
118*57718be8SEnji Cooper 
119*57718be8SEnji Cooper 		break;
120*57718be8SEnji Cooper 	case INQUIRY: {
121*57718be8SEnji Cooper 		struct scsipi_inquiry_data *inqbuf = (void *)xs->data;
122*57718be8SEnji Cooper 
123*57718be8SEnji Cooper 		memset(inqbuf, 0, sizeof(*inqbuf));
124*57718be8SEnji Cooper 		inqbuf->device = T_CDROM;
125*57718be8SEnji Cooper 		inqbuf->dev_qual2 = SID_REMOVABLE;
126*57718be8SEnji Cooper 		strcpy(inqbuf->vendor, "RUMPHOBO");
127*57718be8SEnji Cooper 		strcpy(inqbuf->product, "It's a LIE");
128*57718be8SEnji Cooper 		strcpy(inqbuf->revision, "0.00");
129*57718be8SEnji Cooper 		break;
130*57718be8SEnji Cooper 	}
131*57718be8SEnji Cooper 	case READ_CD_CAPACITY: {
132*57718be8SEnji Cooper 		struct scsipi_read_cd_cap_data *ret = (void *)xs->data;
133*57718be8SEnji Cooper 
134*57718be8SEnji Cooper 		_lto4b(CDBLOCKSIZE, ret->length);
135*57718be8SEnji Cooper 		_lto4b(mycdsize, ret->addr);
136*57718be8SEnji Cooper 
137*57718be8SEnji Cooper 		break;
138*57718be8SEnji Cooper 	}
139*57718be8SEnji Cooper 	case READ_DISCINFO: {
140*57718be8SEnji Cooper 		struct scsipi_read_discinfo_data *ret = (void *)xs->data;
141*57718be8SEnji Cooper 
142*57718be8SEnji Cooper 		memset(ret, 0, sizeof(*ret));
143*57718be8SEnji Cooper 		break;
144*57718be8SEnji Cooper 	}
145*57718be8SEnji Cooper 	case READ_TRACKINFO: {
146*57718be8SEnji Cooper 		struct scsipi_read_trackinfo_data *ret = (void *)xs->data;
147*57718be8SEnji Cooper 
148*57718be8SEnji Cooper 		_lto4b(mycdsize, ret->track_size);
149*57718be8SEnji Cooper 		break;
150*57718be8SEnji Cooper 	}
151*57718be8SEnji Cooper 	case READ_TOC: {
152*57718be8SEnji Cooper 		struct scsipi_toc_header *ret = (void *)xs->data;
153*57718be8SEnji Cooper 
154*57718be8SEnji Cooper 		memset(ret, 0, sizeof(*ret));
155*57718be8SEnji Cooper 		break;
156*57718be8SEnji Cooper 	}
157*57718be8SEnji Cooper 	case START_STOP: {
158*57718be8SEnji Cooper 		struct scsipi_start_stop *param = (void *)cmd;
159*57718be8SEnji Cooper 
160*57718be8SEnji Cooper 		if (param->how & SSS_LOEJ) {
161*57718be8SEnji Cooper #ifdef USE_TOSI_ISO
162*57718be8SEnji Cooper 			rumpuser_close(isofd, &error);
163*57718be8SEnji Cooper #endif
164*57718be8SEnji Cooper 			isofd = -1;
165*57718be8SEnji Cooper 		}
166*57718be8SEnji Cooper 		break;
167*57718be8SEnji Cooper 	}
168*57718be8SEnji Cooper 	case SCSI_SYNCHRONIZE_CACHE_10: {
169*57718be8SEnji Cooper 		if (isofd == -1) {
170*57718be8SEnji Cooper 			if ((xs->xs_control & XS_CTL_SILENT) == 0)
171*57718be8SEnji Cooper 				atomic_inc_uint(&rump_scsitest_err
172*57718be8SEnji Cooper 				    [RUMP_SCSITEST_NOISYSYNC]);
173*57718be8SEnji Cooper 
174*57718be8SEnji Cooper 			sense_notready(xs);
175*57718be8SEnji Cooper 		}
176*57718be8SEnji Cooper 
177*57718be8SEnji Cooper 		break;
178*57718be8SEnji Cooper 	}
179*57718be8SEnji Cooper 	case GET_CONFIGURATION: {
180*57718be8SEnji Cooper 		memset(xs->data, 0, sizeof(struct scsipi_get_conf_data));
181*57718be8SEnji Cooper 		break;
182*57718be8SEnji Cooper 	}
183*57718be8SEnji Cooper 	case SCSI_READ_6_COMMAND: {
184*57718be8SEnji Cooper #ifdef USE_TOSI_ISO
185*57718be8SEnji Cooper 		struct scsi_rw_6 *param = (void *)cmd;
186*57718be8SEnji Cooper 
187*57718be8SEnji Cooper 		printf("reading %d bytes from %d\n",
188*57718be8SEnji Cooper 		    param->length * CDBLOCKSIZE,
189*57718be8SEnji Cooper 		    _3btol(param->addr) * CDBLOCKSIZE);
190*57718be8SEnji Cooper 		rumpuser_pread(isofd, xs->data,
191*57718be8SEnji Cooper 		     param->length * CDBLOCKSIZE,
192*57718be8SEnji Cooper 		     _3btol(param->addr) * CDBLOCKSIZE,
193*57718be8SEnji Cooper 		     &error);
194*57718be8SEnji Cooper #endif
195*57718be8SEnji Cooper 
196*57718be8SEnji Cooper 		break;
197*57718be8SEnji Cooper 	}
198*57718be8SEnji Cooper 	case SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL:
199*57718be8SEnji Cooper 		/* hardcoded for now */
200*57718be8SEnji Cooper 		break;
201*57718be8SEnji Cooper 	default:
202*57718be8SEnji Cooper 		printf("unhandled opcode 0x%x\n", cmd->opcode);
203*57718be8SEnji Cooper 		break;
204*57718be8SEnji Cooper 	}
205*57718be8SEnji Cooper 
206*57718be8SEnji Cooper 	scsipi_done(xs);
207*57718be8SEnji Cooper }
208*57718be8SEnji Cooper 
209*57718be8SEnji Cooper int
scsitest_match(device_t parent,cfdata_t match,void * aux)210*57718be8SEnji Cooper scsitest_match(device_t parent, cfdata_t match, void *aux)
211*57718be8SEnji Cooper {
212*57718be8SEnji Cooper #ifdef USE_TOSI_ISO
213*57718be8SEnji Cooper 	uint64_t fsize;
214*57718be8SEnji Cooper 	int error, ft;
215*57718be8SEnji Cooper 
216*57718be8SEnji Cooper 	if (rumpuser_getfileinfo(MYCDISO, &fsize, &ft, &error))
217*57718be8SEnji Cooper 		return 0;
218*57718be8SEnji Cooper 	if (ft != RUMPUSER_FT_REG)
219*57718be8SEnji Cooper 		return 0;
220*57718be8SEnji Cooper 	mycdsize = fsize / CDBLOCKSIZE;
221*57718be8SEnji Cooper 
222*57718be8SEnji Cooper 	if ((isofd = rumpuser_open(MYCDISO, RUMPUSER_OPEN_RDWR, &error)) == -1)
223*57718be8SEnji Cooper 		return 0;
224*57718be8SEnji Cooper #else
225*57718be8SEnji Cooper 	/*
226*57718be8SEnji Cooper 	 * We pretend to have a medium present initially, so != -1.
227*57718be8SEnji Cooper 	 */
228*57718be8SEnji Cooper 	isofd = -2;
229*57718be8SEnji Cooper #endif
230*57718be8SEnji Cooper 
231*57718be8SEnji Cooper 	return 1;
232*57718be8SEnji Cooper }
233*57718be8SEnji Cooper 
234*57718be8SEnji Cooper void
scsitest_attach(device_t parent,device_t self,void * aux)235*57718be8SEnji Cooper scsitest_attach(device_t parent, device_t self, void *aux)
236*57718be8SEnji Cooper {
237*57718be8SEnji Cooper 	struct scsitest *sc = device_private(self);
238*57718be8SEnji Cooper 
239*57718be8SEnji Cooper 	aprint_naive("\n");
240*57718be8SEnji Cooper 	aprint_normal("\n");
241*57718be8SEnji Cooper 
242*57718be8SEnji Cooper 	memset(&sc->sc_adapter, 0, sizeof(sc->sc_adapter));
243*57718be8SEnji Cooper 	sc->sc_adapter.adapt_nchannels = 1;
244*57718be8SEnji Cooper 	sc->sc_adapter.adapt_request = scsitest_request;
245*57718be8SEnji Cooper 	sc->sc_adapter.adapt_minphys = minphys;
246*57718be8SEnji Cooper 	sc->sc_adapter.adapt_dev = self;
247*57718be8SEnji Cooper 	sc->sc_adapter.adapt_max_periph = 1;
248*57718be8SEnji Cooper 	sc->sc_adapter.adapt_openings = 1;
249*57718be8SEnji Cooper 
250*57718be8SEnji Cooper 	memset(&sc->sc_channel, 0, sizeof(sc->sc_channel));
251*57718be8SEnji Cooper 	sc->sc_channel.chan_bustype = &scsi_bustype;
252*57718be8SEnji Cooper 	sc->sc_channel.chan_ntargets = 2;
253*57718be8SEnji Cooper 	sc->sc_channel.chan_nluns = 1;
254*57718be8SEnji Cooper 	sc->sc_channel.chan_id = 0;
255*57718be8SEnji Cooper 	sc->sc_channel.chan_flags = SCSIPI_CHAN_NOSETTLE;
256*57718be8SEnji Cooper 	sc->sc_channel.chan_adapter = &sc->sc_adapter;
257*57718be8SEnji Cooper 
258*57718be8SEnji Cooper 	config_found_ia(self, "scsi", &sc->sc_channel, scsiprint);
259*57718be8SEnji Cooper }
260