FreeBSD/Linux Kernel Cross Reference
sys/scsi/su.c
1 /* su: SCSI Universal. This is a universal SCSI device that
2 * has a fixed minor number format. This allows you to refer
3 * to your devices by BUS, ID, LUN instead of st0, st1, ...
4 *
5 * This code looks up the underlying device for a given SCSI
6 * target and uses that driver.
7 *
8 *Begin copyright
9 *
10 * Copyright (C) 1993, 1994, 1995, HD Associates, Inc.
11 * PO Box 276
12 * Pepperell, MA 01463
13 * 508 433 5266
14 * dufault@hda.com
15 *
16 * This code is contributed to the University of California at Berkeley:
17 *
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions
20 * are met:
21 * 1. Redistributions of source code must retain the above copyright
22 * notice, this list of conditions and the following disclaimer.
23 * 2. Redistributions in binary form must reproduce the above copyright
24 * notice, this list of conditions and the following disclaimer in the
25 * documentation and/or other materials provided with the distribution.
26 * 3. All advertising materials mentioning features or use of this software
27 * must display the following acknowledgement:
28 * This product includes software developed by the University of
29 * California, Berkeley and its contributors.
30 * 4. Neither the name of the University nor the names of its contributors
31 * may be used to endorse or promote products derived from this software
32 * without specific prior written permission.
33 *
34 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
35 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 * SUCH DAMAGE.
45 *End copyright
46 *
47 * $FreeBSD: src/sys/scsi/su.c,v 1.14.4.1 1999/09/05 08:21:52 peter Exp $
48 *
49 * Tabstops 4
50 * XXX devfs entries for this device should be handled by generic scsiconfig
51 * Add a bdevsw interface.. ?
52 */
53
54 #include <sys/param.h>
55 #include <sys/conf.h>
56 #include <sys/errno.h>
57 #include <sys/stat.h>
58 #include <sys/param.h>
59 #include <sys/buf.h>
60 #include <sys/systm.h>
61 #include <sys/kernel.h>
62 #ifdef DEVFS
63 #include <sys/devfsext.h>
64 #endif /*DEVFS*/
65 #include <scsi/scsiconf.h>
66 #define CDEV_MAJOR 18
67
68 /* These three used by ssc. */
69 extern d_open_t suopen;
70 extern d_close_t suclose;
71 extern d_ioctl_t suioctl;
72
73 static d_read_t suread;
74 static d_write_t suwrite;
75 static d_select_t suselect;
76 static d_strategy_t sustrategy;
77
78 static struct cdevsw su_cdevsw =
79 { suopen, suclose, suread, suwrite, /*18*/
80 suioctl, nostop, nullreset, nodevtotty,/* scsi */
81 suselect, nommap, sustrategy, "su", NULL, -1 };
82
83
84 /* Build an old style device number (unit encoded in the minor number)
85 * from a base old one (no flag bits) and a full new one
86 * (BUS, LUN, TARG in the minor number, and flag bits).
87 *
88 * OLDDEV has the major number and device unit only. It was constructed
89 * at attach time and is stored in the scsi_link structure.
90 *
91 * NEWDEV can have whatever in it, but only the old control flags and the
92 * super bit are present. IT CAN'T HAVE ANY UNIT INFORMATION or you'll
93 * wind up with the wrong unit.
94 */
95 #define OLD_DEV(NEWDEV, OLDDEV) ((OLDDEV) | ((NEWDEV) & 0x080000FF))
96
97 /* bnxio, cnxio: non existent device entries
98 */
99 static struct bdevsw bnxio = {
100 nxopen,
101 nxclose,
102 nxstrategy,
103 nxioctl,
104 nxdump,
105 nxpsize,
106 0,
107 "NON",
108 NULL,
109 -1
110 };
111
112 static struct cdevsw cnxio = {
113 nxopen,
114 nxclose,
115 nxread,
116 nxwrite,
117 nxioctl,
118 nxstop,
119 nxreset,
120 nxdevtotty,
121 nxselect,
122 nxmmap,
123 nxstrategy,
124 "NON",
125 NULL,
126 -1
127 };
128
129 /* getsws: Look up the base dev switch for a given "by minor number" style
130 * device.
131 */
132 static int
133 getsws(dev_t dev, int type,
134 struct bdevsw **bdevp, struct cdevsw **cdevp, dev_t *base)
135 {
136 int ret = 0;
137 struct scsi_link *scsi_link;
138 int chr_dev, blk_dev;
139
140 struct cdevsw *cdev;
141 struct bdevsw *bdev;
142
143 int bus = SCSI_BUS(dev),
144 lun = SCSI_LUN(dev),
145 id = SCSI_ID(dev);
146
147 /* Try to look up the base device by finding the major number in
148 * the scsi_link structure:
149 */
150 if ((scsi_link = scsi_link_get(bus, id, lun)) == 0 ||
151 scsi_link->dev == NODEV)
152 {
153 ret = ENXIO;
154
155 /* XXX This assumes that you always have a character device if you
156 * have a block device. That seems reasonable.
157 */
158 cdev = &cnxio;
159 chr_dev = NODEV;
160 bdev = &bnxio;
161 blk_dev = NODEV;
162 }
163 else
164 {
165 int bmaj, cmaj;
166
167 cmaj = major(scsi_link->dev);
168 cdev = cdevsw[cmaj];
169 chr_dev = OLD_DEV(dev, scsi_link->dev);
170
171 bmaj = chrtoblk(cmaj);
172 bdev = (bmaj == NODEV) ? &bnxio : bdevsw[bmaj];
173 blk_dev = OLD_DEV(dev, makedev(bmaj, minor(scsi_link->dev)));
174 }
175
176 if (cdevp)
177 *cdevp = cdev;
178 if (bdevp)
179 *bdevp = bdev;
180
181 if (type == S_IFCHR)
182 *base = chr_dev;
183 else
184 *base = blk_dev;
185
186 return ret;
187 }
188
189 int
190 suopen(dev_t dev, int flag, int type, struct proc *p)
191 {
192 struct cdevsw *cdev;
193 struct bdevsw *bdev;
194 dev_t base;
195
196 if (getsws(dev, type, &bdev, &cdev, &base))
197 {
198 /* Device not configured? Reprobe then try again.
199 */
200 int bus = SCSI_BUS(dev), lun = SCSI_LUN(dev), id = SCSI_ID(dev);
201
202 if (scsi_probe_bus(bus, id, lun) || getsws(dev, type, &bdev, &cdev,
203 &base))
204 return ENXIO;
205 }
206
207 /* There is a properly configured underlying device.
208 * Synthesize an appropriate device number:
209 */
210 if (type == S_IFCHR)
211 return (*cdev->d_open)(base, flag, S_IFCHR, p);
212 else
213 return (*bdev->d_open)(base, flag, S_IFBLK, p);
214 }
215
216 int
217 suclose(dev_t dev, int fflag, int type, struct proc *p)
218 {
219 struct cdevsw *cdev;
220 struct bdevsw *bdev;
221 dev_t base;
222
223 (void)getsws(dev, type, &bdev, &cdev, &base);
224
225 if (type == S_IFCHR)
226 return (*cdev->d_close)(base, fflag, S_IFCHR, p);
227 else
228 return (*bdev->d_open)(base, fflag, S_IFBLK, p);
229 }
230
231 static void
232 sustrategy(struct buf *bp)
233 {
234 dev_t base;
235 struct bdevsw *bdev;
236 dev_t dev = bp->b_dev;
237
238 /* XXX: I have no way of knowing if this was through the
239 * block or the character entry point.
240 */
241 (void)getsws(dev, S_IFBLK, &bdev, 0, &base);
242
243 bp->b_dev = base;
244
245 (*bdev->d_strategy)(bp);
246
247 bp->b_dev = dev;
248 }
249
250 int
251 suioctl(dev_t dev, int cmd, caddr_t data, int fflag, struct proc *p)
252 {
253 struct cdevsw *cdev;
254 dev_t base;
255
256 /* XXX: I have no way of knowing if this was through the
257 * block or the character entry point.
258 */
259 (void)getsws(dev, S_IFCHR, 0, &cdev, &base);
260
261 return (*cdev->d_ioctl)(base, cmd, data, fflag, p);
262 }
263
264 static int
265 suread(dev_t dev, struct uio *uio, int ioflag)
266 {
267 dev_t base;
268 struct cdevsw *cdev;
269
270 (void)getsws(dev, S_IFCHR, 0, &cdev, &base);
271
272 return (*cdev->d_read)(base, uio, ioflag);
273 }
274
275 static int
276 suwrite(dev_t dev, struct uio *uio, int ioflag)
277 {
278 dev_t base;
279 struct cdevsw *cdev;
280
281 (void)getsws(dev, S_IFCHR, 0, &cdev, &base);
282
283 return (*cdev->d_write)(base, uio, ioflag);
284 }
285
286 static int
287 suselect(dev_t dev, int which, struct proc *p)
288 {
289 dev_t base;
290 struct cdevsw *cdev;
291
292 (void)getsws(dev, S_IFCHR, 0, &cdev, &base);
293
294 return (*cdev->d_select)(base, which, p);
295 }
296
297 static su_devsw_installed = 0;
298
299 static void
300 su_drvinit(void *unused)
301 {
302 dev_t dev;
303
304 if( ! su_devsw_installed ) {
305 dev = makedev(CDEV_MAJOR, 0);
306 cdevsw_add(&dev,&su_cdevsw, NULL);
307 su_devsw_installed = 1;
308 }
309 }
310
311 SYSINIT(sudev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,su_drvinit,NULL)
312
313
Cache object: 5636ae402a04b249071692e4a417985b
|