Commit | Line | Data |
---|---|---|
60f56dfc | 1 | /* |
030a8056 KB |
2 | * Copyright (c) 1990, 1993 |
3 | * The Regents of the University of California. All rights reserved. | |
60f56dfc KM |
4 | * |
5 | * This code is derived from software contributed to Berkeley by | |
6 | * Van Jacobson of Lawrence Berkeley Laboratory. | |
7 | * | |
ad787160 C |
8 | * Redistribution and use in source and binary forms, with or without |
9 | * modification, are permitted provided that the following conditions | |
10 | * are met: | |
11 | * 1. Redistributions of source code must retain the above copyright | |
12 | * notice, this list of conditions and the following disclaimer. | |
13 | * 2. Redistributions in binary form must reproduce the above copyright | |
14 | * notice, this list of conditions and the following disclaimer in the | |
15 | * documentation and/or other materials provided with the distribution. | |
16 | * 3. All advertising materials mentioning features or use of this software | |
17 | * must display the following acknowledgement: | |
18 | * This product includes software developed by the University of | |
19 | * California, Berkeley and its contributors. | |
20 | * 4. Neither the name of the University nor the names of its contributors | |
21 | * may be used to endorse or promote products derived from this software | |
22 | * without specific prior written permission. | |
60f56dfc | 23 | * |
ad787160 C |
24 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
25 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
28 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
29 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
30 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
32 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
33 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
34 | * SUCH DAMAGE. | |
35 | * | |
fd88f5c5 | 36 | * @(#)sd.c 8.9 (Berkeley) 5/14/95 |
60f56dfc KM |
37 | */ |
38 | ||
39 | /* | |
40 | * SCSI CCS (Command Command Set) disk driver. | |
41 | */ | |
42 | #include "sd.h" | |
43 | #if NSD > 0 | |
44 | ||
45 | #ifndef lint | |
4bcb05ed | 46 | static char rcsid[] = "$Header: /sys.lite/hp300/dev/RCS/sd.c,v 1.2 1994/01/10 18:29:19 mike Exp mike $"; |
60f56dfc KM |
47 | #endif |
48 | ||
38a01dbe KB |
49 | #include <sys/param.h> |
50 | #include <sys/systm.h> | |
51 | #include <sys/buf.h> | |
573b5fae | 52 | #include <sys/stat.h> |
38a01dbe KB |
53 | #include <sys/dkstat.h> |
54 | #include <sys/disklabel.h> | |
55 | #include <sys/malloc.h> | |
56 | #include <sys/proc.h> | |
57 | #include <sys/ioctl.h> | |
573b5fae | 58 | #include <sys/fcntl.h> |
60f56dfc | 59 | |
38a01dbe KB |
60 | #include <hp/dev/device.h> |
61 | #include <hp300/dev/scsireg.h> | |
573b5fae MH |
62 | #include <hp300/dev/sdvar.h> |
63 | #ifdef USELEDS | |
64 | #include <hp300/hp300/led.h> | |
65 | #endif | |
38a01dbe | 66 | |
7fee1787 | 67 | #include <vm/vm.h> |
22d09b27 | 68 | |
60f56dfc KM |
69 | extern int scsi_test_unit_rdy(); |
70 | extern int scsi_request_sense(); | |
71 | extern int scsi_inquiry(); | |
72 | extern int scsi_read_capacity(); | |
73 | extern int scsi_tt_write(); | |
74 | extern int scsireq(); | |
75 | extern int scsiustart(); | |
76 | extern int scsigo(); | |
77 | extern void scsifree(); | |
78 | extern void scsireset(); | |
98d7aa4d | 79 | extern void scsi_delay(); |
60f56dfc | 80 | |
60f56dfc | 81 | extern void disksort(); |
60f56dfc KM |
82 | extern void biodone(); |
83 | extern int physio(); | |
84 | extern void TBIS(); | |
85 | ||
86 | int sdinit(); | |
87 | void sdstrategy(), sdstart(), sdustart(), sdgo(), sdintr(); | |
88 | ||
89 | struct driver sddriver = { | |
90 | sdinit, "sd", (int (*)())sdstart, (int (*)())sdgo, (int (*)())sdintr, | |
91 | }; | |
92 | ||
60f56dfc KM |
93 | #ifdef DEBUG |
94 | int sddebug = 1; | |
95 | #define SDB_ERROR 0x01 | |
96 | #define SDB_PARTIAL 0x02 | |
4bcb05ed | 97 | #define SDB_CAPACITY 0x04 |
60f56dfc KM |
98 | #endif |
99 | ||
573b5fae MH |
100 | struct sd_softc sd_softc[NSD]; |
101 | struct sdstats sdstats[NSD]; | |
60f56dfc | 102 | struct buf sdtab[NSD]; |
60f56dfc KM |
103 | struct scsi_fmt_cdb sdcmd[NSD]; |
104 | struct scsi_fmt_sense sdsense[NSD]; | |
105 | ||
106 | static struct scsi_fmt_cdb sd_read_cmd = { 10, CMD_READ_EXT }; | |
107 | static struct scsi_fmt_cdb sd_write_cmd = { 10, CMD_WRITE_EXT }; | |
108 | ||
60f56dfc KM |
109 | /* |
110 | * Table of scsi commands users are allowed to access via "format" | |
111 | * mode. 0 means not legal. 1 means "immediate" (doesn't need dma). | |
112 | * -1 means needs dma and/or wait for intr. | |
113 | */ | |
114 | static char legal_cmds[256] = { | |
115 | /***** 0 1 2 3 4 5 6 7 8 9 A B C D E F */ | |
116 | /*00*/ 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
117 | /*10*/ 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, | |
118 | /*20*/ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
119 | /*30*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
120 | /*40*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
121 | /*50*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
122 | /*60*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
123 | /*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
124 | /*80*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
125 | /*90*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
126 | /*a0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
127 | /*b0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
128 | /*c0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
129 | /*d0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
130 | /*e0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
131 | /*f0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
132 | }; | |
133 | ||
134 | static struct scsi_inquiry inqbuf; | |
135 | static struct scsi_fmt_cdb inq = { | |
136 | 6, | |
137 | CMD_INQUIRY, 0, 0, 0, sizeof(inqbuf), 0 | |
138 | }; | |
139 | ||
60f56dfc KM |
140 | static int |
141 | sdident(sc, hd) | |
142 | struct sd_softc *sc; | |
143 | struct hp_device *hd; | |
144 | { | |
145 | int unit; | |
146 | register int ctlr, slave; | |
147 | register int i; | |
148 | register int tries = 10; | |
98d7aa4d | 149 | char idstr[32]; |
4bcb05ed | 150 | int isrm = 0; |
60f56dfc KM |
151 | |
152 | ctlr = hd->hp_ctlr; | |
153 | slave = hd->hp_slave; | |
154 | unit = sc->sc_punit; | |
98d7aa4d | 155 | scsi_delay(-1); |
60f56dfc KM |
156 | |
157 | /* | |
158 | * See if unit exists and is a disk then read block size & nblocks. | |
159 | */ | |
160 | while ((i = scsi_test_unit_rdy(ctlr, slave, unit)) != 0) { | |
22d09b27 | 161 | if (i == -1 || --tries < 0) { |
4bcb05ed | 162 | if (isrm) |
22d09b27 | 163 | break; |
60f56dfc | 164 | /* doesn't exist or not a CCS device */ |
98d7aa4d | 165 | goto failed; |
22d09b27 | 166 | } |
60f56dfc KM |
167 | if (i == STS_CHECKCOND) { |
168 | u_char sensebuf[128]; | |
169 | struct scsi_xsense *sp = (struct scsi_xsense *)sensebuf; | |
170 | ||
171 | scsi_request_sense(ctlr, slave, unit, sensebuf, | |
172 | sizeof(sensebuf)); | |
22d09b27 KM |
173 | if (sp->class == 7) |
174 | switch (sp->key) { | |
4bcb05ed MH |
175 | /* |
176 | * Not ready -- might be removable media | |
177 | * device with no media. Assume as much, | |
178 | * if it really isn't, the inquiry commmand | |
179 | * below will fail. | |
180 | */ | |
22d09b27 | 181 | case 2: |
4bcb05ed | 182 | isrm = 1; |
22d09b27 | 183 | break; |
60f56dfc | 184 | /* drive doing an RTZ -- give it a while */ |
22d09b27 KM |
185 | case 6: |
186 | DELAY(1000000); | |
187 | break; | |
188 | default: | |
189 | break; | |
190 | } | |
60f56dfc KM |
191 | } |
192 | DELAY(1000); | |
193 | } | |
22d09b27 KM |
194 | /* |
195 | * Find out about device | |
196 | */ | |
197 | if (scsi_immed_command(ctlr, slave, unit, &inq, | |
198 | (u_char *)&inqbuf, sizeof(inqbuf), B_READ)) | |
98d7aa4d | 199 | goto failed; |
60f56dfc KM |
200 | switch (inqbuf.type) { |
201 | case 0: /* disk */ | |
202 | case 4: /* WORM */ | |
203 | case 5: /* CD-ROM */ | |
204 | case 7: /* Magneto-optical */ | |
205 | break; | |
206 | default: /* not a disk */ | |
98d7aa4d | 207 | goto failed; |
60f56dfc | 208 | } |
22d09b27 | 209 | /* |
98d7aa4d | 210 | * Get a usable id string |
22d09b27 | 211 | */ |
573b5fae MH |
212 | switch (inqbuf.version) { |
213 | case 1: | |
214 | case 2: | |
98d7aa4d MH |
215 | bcopy((caddr_t)&inqbuf.vendor_id, (caddr_t)idstr, 28); |
216 | for (i = 27; i > 23; --i) | |
217 | if (idstr[i] != ' ') | |
218 | break; | |
219 | idstr[i+1] = 0; | |
220 | for (i = 23; i > 7; --i) | |
221 | if (idstr[i] != ' ') | |
222 | break; | |
223 | idstr[i+1] = 0; | |
224 | for (i = 7; i >= 0; --i) | |
225 | if (idstr[i] != ' ') | |
226 | break; | |
227 | idstr[i+1] = 0; | |
573b5fae MH |
228 | break; |
229 | default: | |
230 | bcopy("UNKNOWN", &idstr[0], 8); | |
231 | bcopy("DRIVE TYPE", &idstr[8], 11); | |
22d09b27 | 232 | } |
4bcb05ed MH |
233 | if (inqbuf.qual & 0x80) |
234 | sc->sc_flags |= SDF_RMEDIA; | |
235 | ||
236 | if (sdgetcapacity(sc, hd, NODEV) < 0) | |
237 | goto failed; | |
60f56dfc | 238 | |
573b5fae MH |
239 | switch (inqbuf.version) { |
240 | case 1: | |
241 | case 2: | |
60f56dfc KM |
242 | printf("sd%d: %s %s rev %s", hd->hp_unit, idstr, &idstr[8], |
243 | &idstr[24]); | |
573b5fae MH |
244 | if (inqbuf.version == 2) |
245 | printf(" (SCSI-2)"); | |
246 | break; | |
247 | default: | |
248 | printf("sd%d: type 0x%x, qual 0x%x, ver %d", hd->hp_unit, | |
249 | inqbuf.type, inqbuf.qual, inqbuf.version); | |
250 | break; | |
251 | } | |
4bcb05ed MH |
252 | if (sc->sc_blks) |
253 | printf(", %d %d byte blocks", | |
254 | sc->sc_blks >> sc->sc_bshift, sc->sc_blksize); | |
255 | printf("\n"); | |
60f56dfc | 256 | sc->sc_wpms = 32 * (60 * DEV_BSIZE / 2); /* XXX */ |
98d7aa4d | 257 | scsi_delay(0); |
60f56dfc | 258 | return(inqbuf.type); |
98d7aa4d MH |
259 | failed: |
260 | scsi_delay(0); | |
261 | return(-1); | |
60f56dfc KM |
262 | } |
263 | ||
264 | int | |
265 | sdinit(hd) | |
266 | register struct hp_device *hd; | |
267 | { | |
268 | register struct sd_softc *sc = &sd_softc[hd->hp_unit]; | |
269 | ||
270 | sc->sc_hd = hd; | |
9acfa6cd | 271 | sc->sc_flags = 0; |
0fb33df5 MH |
272 | /* |
273 | * XXX formerly 0 meant unused but now pid 0 can legitimately | |
274 | * use this interface (sdgetcapacity). | |
275 | */ | |
276 | sc->sc_format_pid = -1; | |
60f56dfc KM |
277 | sc->sc_punit = sdpunit(hd->hp_flags); |
278 | sc->sc_type = sdident(sc, hd); | |
279 | if (sc->sc_type < 0) | |
280 | return(0); | |
281 | sc->sc_dq.dq_ctlr = hd->hp_ctlr; | |
282 | sc->sc_dq.dq_unit = hd->hp_unit; | |
283 | sc->sc_dq.dq_slave = hd->hp_slave; | |
284 | sc->sc_dq.dq_driver = &sddriver; | |
285 | ||
9acfa6cd | 286 | sc->sc_flags |= SDF_ALIVE; |
60f56dfc KM |
287 | return(1); |
288 | } | |
289 | ||
290 | void | |
291 | sdreset(sc, hd) | |
292 | register struct sd_softc *sc; | |
293 | register struct hp_device *hd; | |
294 | { | |
295 | sdstats[hd->hp_unit].sdresets++; | |
296 | } | |
297 | ||
4bcb05ed MH |
298 | /* |
299 | * Determine capacity of a drive. | |
300 | * Returns -1 on a failure, 0 on success, 1 on a failure that is probably | |
301 | * due to missing media. | |
302 | */ | |
303 | int | |
304 | sdgetcapacity(sc, hd, dev) | |
305 | struct sd_softc *sc; | |
306 | struct hp_device *hd; | |
307 | dev_t dev; | |
308 | { | |
309 | static struct scsi_fmt_cdb cap = { | |
310 | 10, | |
311 | CMD_READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0 | |
312 | }; | |
0fb33df5 MH |
313 | u_char *capbuf; |
314 | int i, capbufsize; | |
315 | ||
316 | /* | |
317 | * Cannot use stack space for this buffer since stack KVA may not | |
318 | * be valid (i.e. in context of this process) when the operation | |
319 | * actually starts. | |
320 | */ | |
321 | capbufsize = 8; | |
322 | capbuf = malloc(capbufsize, M_DEVBUF, M_WAITOK); | |
4bcb05ed MH |
323 | |
324 | if (dev == NODEV) { | |
325 | i = scsi_immed_command(hd->hp_ctlr, hd->hp_slave, sc->sc_punit, | |
0fb33df5 | 326 | &cap, capbuf, capbufsize, B_READ); |
4bcb05ed | 327 | } else { |
0fb33df5 MH |
328 | struct buf *bp; |
329 | ||
4bcb05ed MH |
330 | /* |
331 | * XXX this is horrible | |
332 | */ | |
0fb33df5 | 333 | if (sc->sc_format_pid >= 0) |
4bcb05ed | 334 | panic("sdgetcapacity"); |
0fb33df5 | 335 | bp = malloc(sizeof *bp, M_DEVBUF, M_WAITOK); |
4bcb05ed MH |
336 | sc->sc_format_pid = curproc->p_pid; |
337 | bcopy((caddr_t)&cap, (caddr_t)&sdcmd[hd->hp_unit], sizeof cap); | |
0fb33df5 MH |
338 | bp->b_dev = dev; |
339 | bp->b_flags = B_READ | B_BUSY; | |
340 | bp->b_un.b_addr = (caddr_t)capbuf; | |
341 | bp->b_bcount = capbufsize; | |
342 | sdstrategy(bp); | |
343 | i = biowait(bp) ? sdsense[hd->hp_unit].status : 0; | |
344 | free(bp, M_DEVBUF); | |
345 | sc->sc_format_pid = -1; | |
4bcb05ed MH |
346 | } |
347 | if (i) { | |
348 | if (i != STS_CHECKCOND || (sc->sc_flags & SDF_RMEDIA) == 0) { | |
349 | #ifdef DEBUG | |
350 | if (sddebug & SDB_CAPACITY) | |
351 | printf("sd%d: read_capacity returns %d\n", | |
352 | hd->hp_unit, i); | |
353 | #endif | |
0fb33df5 | 354 | free(capbuf, M_DEVBUF); |
4bcb05ed MH |
355 | return (-1); |
356 | } | |
357 | /* | |
358 | * XXX assume unformatted or non-existant media | |
359 | */ | |
360 | sc->sc_blks = 0; | |
361 | sc->sc_blksize = DEV_BSIZE; | |
362 | sc->sc_bshift = 0; | |
363 | #ifdef DEBUG | |
364 | if (sddebug & SDB_CAPACITY) | |
365 | printf("sd%d: removable media not present\n", | |
366 | hd->hp_unit); | |
367 | #endif | |
0fb33df5 | 368 | free(capbuf, M_DEVBUF); |
4bcb05ed MH |
369 | return (1); |
370 | } | |
371 | sc->sc_blks = *(u_int *)&capbuf[0]; | |
372 | sc->sc_blksize = *(int *)&capbuf[4]; | |
0fb33df5 | 373 | free(capbuf, M_DEVBUF); |
4bcb05ed MH |
374 | sc->sc_bshift = 0; |
375 | ||
376 | /* return value of read capacity is last valid block number */ | |
377 | sc->sc_blks++; | |
378 | ||
379 | if (sc->sc_blksize != DEV_BSIZE) { | |
380 | if (sc->sc_blksize < DEV_BSIZE) { | |
0fb33df5 MH |
381 | printf("sd%d: need at least %d byte blocks - %s\n", |
382 | hd->hp_unit, DEV_BSIZE, "drive ignored"); | |
4bcb05ed MH |
383 | return (-1); |
384 | } | |
385 | for (i = sc->sc_blksize; i > DEV_BSIZE; i >>= 1) | |
386 | ++sc->sc_bshift; | |
387 | sc->sc_blks <<= sc->sc_bshift; | |
388 | } | |
389 | #ifdef DEBUG | |
390 | if (sddebug & SDB_CAPACITY) | |
391 | printf("sd%d: blks=%d, blksize=%d, bshift=%d\n", hd->hp_unit, | |
392 | sc->sc_blks, sc->sc_blksize, sc->sc_bshift); | |
393 | #endif | |
394 | return (0); | |
395 | } | |
396 | ||
573b5fae MH |
397 | /* |
398 | * Read or constuct a disklabel | |
399 | */ | |
400 | int | |
401 | sdgetinfo(dev) | |
402 | dev_t dev; | |
403 | { | |
404 | int unit = sdunit(dev); | |
405 | register struct sd_softc *sc = &sd_softc[unit]; | |
406 | register struct disklabel *lp = &sc->sc_info.si_label; | |
407 | register struct partition *pi; | |
408 | char *msg, *readdisklabel(); | |
4bcb05ed MH |
409 | #ifdef COMPAT_NOLABEL |
410 | int usedefault = 1; | |
573b5fae MH |
411 | |
412 | /* | |
4bcb05ed | 413 | * For CD-ROM just define a single partition |
573b5fae | 414 | */ |
4bcb05ed MH |
415 | if (sc->sc_type == 5) |
416 | usedefault = 0; | |
417 | #endif | |
418 | ||
573b5fae | 419 | bzero((caddr_t)lp, sizeof *lp); |
4bcb05ed | 420 | msg = NULL; |
573b5fae MH |
421 | |
422 | /* | |
4bcb05ed MH |
423 | * If removable media or the size unavailable at boot time |
424 | * (i.e. unformatted hard disk), attempt to set the capacity | |
425 | * now. | |
573b5fae | 426 | */ |
4bcb05ed MH |
427 | if ((sc->sc_flags & SDF_RMEDIA) || sc->sc_blks == 0) { |
428 | switch (sdgetcapacity(sc, sc->sc_hd, dev)) { | |
429 | case 0: | |
430 | break; | |
431 | case -1: | |
432 | /* | |
433 | * Hard error, just return (open will fail). | |
434 | */ | |
435 | return (EIO); | |
436 | case 1: | |
437 | /* | |
438 | * XXX return 0 so open can continue just in case | |
439 | * the media is unformatted and we want to format it. | |
440 | * We set the error flag so they cannot do much else. | |
441 | */ | |
442 | sc->sc_flags |= SDF_ERROR; | |
443 | msg = "unformatted/missing media"; | |
444 | #ifdef COMPAT_NOLABEL | |
445 | usedefault = 0; | |
446 | #endif | |
447 | break; | |
448 | } | |
449 | } | |
450 | ||
451 | /* | |
452 | * Set some default values to use while reading the label | |
453 | * (or to use if there isn't a label) and try reading it. | |
454 | */ | |
455 | if (msg == NULL) { | |
456 | lp->d_type = DTYPE_SCSI; | |
457 | lp->d_secsize = DEV_BSIZE; | |
458 | lp->d_nsectors = 32; | |
459 | lp->d_ntracks = 20; | |
460 | lp->d_ncylinders = 1; | |
461 | lp->d_secpercyl = 32*20; | |
462 | lp->d_npartitions = 3; | |
463 | lp->d_partitions[2].p_offset = 0; | |
464 | /* XXX we can open a device even without SDF_ALIVE */ | |
465 | if (sc->sc_blksize == 0) | |
466 | sc->sc_blksize = DEV_BSIZE; | |
467 | /* XXX ensure size is at least one device block */ | |
468 | lp->d_partitions[2].p_size = | |
469 | roundup(LABELSECTOR+1, btodb(sc->sc_blksize)); | |
470 | msg = readdisklabel(sdlabdev(dev), sdstrategy, lp); | |
471 | if (msg == NULL) | |
472 | return (0); | |
473 | } | |
573b5fae MH |
474 | |
475 | pi = lp->d_partitions; | |
476 | printf("sd%d: WARNING: %s, ", unit, msg); | |
477 | #ifdef COMPAT_NOLABEL | |
4bcb05ed MH |
478 | if (usedefault) { |
479 | printf("using old default partitioning\n"); | |
480 | sdmakedisklabel(unit, lp); | |
481 | return(0); | |
482 | } | |
483 | #endif | |
573b5fae MH |
484 | printf("defining `c' partition as entire disk\n"); |
485 | pi[2].p_size = sc->sc_blks; | |
d2da96c4 MH |
486 | /* XXX reset other info since readdisklabel screws with it */ |
487 | lp->d_npartitions = 3; | |
488 | pi[0].p_size = 0; | |
573b5fae MH |
489 | return(0); |
490 | } | |
491 | ||
60f56dfc | 492 | int |
88f29710 | 493 | sdopen(dev, flags, mode, p) |
60f56dfc | 494 | dev_t dev; |
88f29710 MK |
495 | int flags, mode; |
496 | struct proc *p; | |
60f56dfc KM |
497 | { |
498 | register int unit = sdunit(dev); | |
499 | register struct sd_softc *sc = &sd_softc[unit]; | |
689a3d14 | 500 | int error, mask; |
60f56dfc | 501 | |
689a3d14 | 502 | if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0) |
60f56dfc | 503 | return(ENXIO); |
60f56dfc | 504 | |
573b5fae MH |
505 | /* |
506 | * Wait for any pending opens/closes to complete | |
507 | */ | |
508 | while (sc->sc_flags & (SDF_OPENING|SDF_CLOSING)) | |
509 | sleep((caddr_t)sc, PRIBIO); | |
689a3d14 | 510 | |
573b5fae MH |
511 | /* |
512 | * On first open, get label and partition info. | |
513 | * We may block reading the label, so be careful | |
514 | * to stop any other opens. | |
515 | */ | |
516 | if (sc->sc_info.si_open == 0) { | |
517 | sc->sc_flags |= SDF_OPENING; | |
518 | error = sdgetinfo(dev); | |
519 | sc->sc_flags &= ~SDF_OPENING; | |
520 | wakeup((caddr_t)sc); | |
521 | if (error) | |
522 | return(error); | |
523 | } | |
60f56dfc KM |
524 | if (sc->sc_hd->hp_dk >= 0) |
525 | dk_wpms[sc->sc_hd->hp_dk] = sc->sc_wpms; | |
573b5fae MH |
526 | |
527 | mask = 1 << sdpart(dev); | |
528 | if (mode == S_IFCHR) | |
529 | sc->sc_info.si_copen |= mask; | |
530 | else | |
531 | sc->sc_info.si_bopen |= mask; | |
532 | sc->sc_info.si_open |= mask; | |
60f56dfc KM |
533 | return(0); |
534 | } | |
535 | ||
9acfa6cd MH |
536 | int |
537 | sdclose(dev, flag, mode, p) | |
538 | dev_t dev; | |
539 | int flag, mode; | |
540 | struct proc *p; | |
541 | { | |
542 | int unit = sdunit(dev); | |
543 | register struct sd_softc *sc = &sd_softc[unit]; | |
573b5fae MH |
544 | register struct sdinfo *si = &sc->sc_info; |
545 | int mask, s; | |
9acfa6cd | 546 | |
573b5fae MH |
547 | mask = 1 << sdpart(dev); |
548 | if (mode == S_IFCHR) | |
549 | si->si_copen &= ~mask; | |
550 | else | |
551 | si->si_bopen &= ~mask; | |
552 | si->si_open = si->si_bopen | si->si_copen; | |
9acfa6cd | 553 | /* |
573b5fae MH |
554 | * On last close, we wait for all activity to cease since |
555 | * the label/parition info will become invalid. Since we | |
556 | * might sleep, we must block any opens while we are here. | |
557 | * Note we don't have to about other closes since we know | |
558 | * we are the last one. | |
9acfa6cd | 559 | */ |
573b5fae MH |
560 | if (si->si_open == 0) { |
561 | sc->sc_flags |= SDF_CLOSING; | |
9acfa6cd MH |
562 | s = splbio(); |
563 | while (sdtab[unit].b_active) { | |
564 | sc->sc_flags |= SDF_WANTED; | |
565 | sleep((caddr_t)&sdtab[unit], PRIBIO); | |
566 | } | |
567 | splx(s); | |
573b5fae MH |
568 | sc->sc_flags &= ~(SDF_CLOSING|SDF_WLABEL|SDF_ERROR); |
569 | wakeup((caddr_t)sc); | |
9acfa6cd | 570 | } |
0fb33df5 | 571 | sc->sc_format_pid = -1; |
573b5fae | 572 | return(0); |
9acfa6cd MH |
573 | } |
574 | ||
60f56dfc KM |
575 | /* |
576 | * This routine is called for partial block transfers and non-aligned | |
577 | * transfers (the latter only being possible on devices with a block size | |
578 | * larger than DEV_BSIZE). The operation is performed in three steps | |
579 | * using a locally allocated buffer: | |
580 | * 1. transfer any initial partial block | |
581 | * 2. transfer full blocks | |
582 | * 3. transfer any final partial block | |
583 | */ | |
584 | static void | |
585 | sdlblkstrat(bp, bsize) | |
586 | register struct buf *bp; | |
587 | register int bsize; | |
588 | { | |
589 | register struct buf *cbp = (struct buf *)malloc(sizeof(struct buf), | |
590 | M_DEVBUF, M_WAITOK); | |
591 | caddr_t cbuf = (caddr_t)malloc(bsize, M_DEVBUF, M_WAITOK); | |
592 | register int bn, resid; | |
593 | register caddr_t addr; | |
594 | ||
595 | bzero((caddr_t)cbp, sizeof(*cbp)); | |
88f29710 | 596 | cbp->b_proc = curproc; /* XXX */ |
60f56dfc KM |
597 | cbp->b_dev = bp->b_dev; |
598 | bn = bp->b_blkno; | |
599 | resid = bp->b_bcount; | |
600 | addr = bp->b_un.b_addr; | |
601 | #ifdef DEBUG | |
602 | if (sddebug & SDB_PARTIAL) | |
603 | printf("sdlblkstrat: bp %x flags %x bn %x resid %x addr %x\n", | |
604 | bp, bp->b_flags, bn, resid, addr); | |
605 | #endif | |
606 | ||
607 | while (resid > 0) { | |
608 | register int boff = dbtob(bn) & (bsize - 1); | |
609 | register int count; | |
610 | ||
611 | if (boff || resid < bsize) { | |
612 | sdstats[sdunit(bp->b_dev)].sdpartials++; | |
479c0df7 | 613 | count = min(resid, bsize - boff); |
60f56dfc KM |
614 | cbp->b_flags = B_BUSY | B_PHYS | B_READ; |
615 | cbp->b_blkno = bn - btodb(boff); | |
616 | cbp->b_un.b_addr = cbuf; | |
617 | cbp->b_bcount = bsize; | |
618 | #ifdef DEBUG | |
619 | if (sddebug & SDB_PARTIAL) | |
620 | printf(" readahead: bn %x cnt %x off %x addr %x\n", | |
621 | cbp->b_blkno, count, boff, addr); | |
622 | #endif | |
623 | sdstrategy(cbp); | |
624 | biowait(cbp); | |
625 | if (cbp->b_flags & B_ERROR) { | |
626 | bp->b_flags |= B_ERROR; | |
627 | bp->b_error = cbp->b_error; | |
628 | break; | |
629 | } | |
630 | if (bp->b_flags & B_READ) { | |
631 | bcopy(&cbuf[boff], addr, count); | |
632 | goto done; | |
633 | } | |
634 | bcopy(addr, &cbuf[boff], count); | |
635 | #ifdef DEBUG | |
636 | if (sddebug & SDB_PARTIAL) | |
637 | printf(" writeback: bn %x cnt %x off %x addr %x\n", | |
638 | cbp->b_blkno, count, boff, addr); | |
639 | #endif | |
640 | } else { | |
641 | count = resid & ~(bsize - 1); | |
642 | cbp->b_blkno = bn; | |
643 | cbp->b_un.b_addr = addr; | |
644 | cbp->b_bcount = count; | |
645 | #ifdef DEBUG | |
646 | if (sddebug & SDB_PARTIAL) | |
647 | printf(" fulltrans: bn %x cnt %x addr %x\n", | |
648 | cbp->b_blkno, count, addr); | |
649 | #endif | |
650 | } | |
651 | cbp->b_flags = B_BUSY | B_PHYS | (bp->b_flags & B_READ); | |
652 | sdstrategy(cbp); | |
653 | biowait(cbp); | |
654 | if (cbp->b_flags & B_ERROR) { | |
655 | bp->b_flags |= B_ERROR; | |
656 | bp->b_error = cbp->b_error; | |
657 | break; | |
658 | } | |
659 | done: | |
660 | bn += btodb(count); | |
661 | resid -= count; | |
662 | addr += count; | |
663 | #ifdef DEBUG | |
664 | if (sddebug & SDB_PARTIAL) | |
665 | printf(" done: bn %x resid %x addr %x\n", | |
666 | bn, resid, addr); | |
667 | #endif | |
668 | } | |
669 | free(cbuf, M_DEVBUF); | |
670 | free(cbp, M_DEVBUF); | |
671 | } | |
672 | ||
673 | void | |
674 | sdstrategy(bp) | |
675 | register struct buf *bp; | |
676 | { | |
573b5fae | 677 | int unit = sdunit(bp->b_dev); |
60f56dfc KM |
678 | register struct sd_softc *sc = &sd_softc[unit]; |
679 | register struct buf *dp = &sdtab[unit]; | |
573b5fae | 680 | register struct partition *pinfo; |
22d09b27 KM |
681 | register daddr_t bn; |
682 | register int sz, s; | |
60f56dfc | 683 | |
0fb33df5 | 684 | if (sc->sc_format_pid >= 0) { |
88f29710 | 685 | if (sc->sc_format_pid != curproc->p_pid) { /* XXX */ |
60f56dfc | 686 | bp->b_error = EPERM; |
573b5fae | 687 | goto bad; |
60f56dfc KM |
688 | } |
689 | bp->b_cylin = 0; | |
690 | } else { | |
4bcb05ed MH |
691 | if (sc->sc_flags & SDF_ERROR) { |
692 | bp->b_error = EIO; | |
693 | goto bad; | |
694 | } | |
60f56dfc | 695 | bn = bp->b_blkno; |
22d09b27 | 696 | sz = howmany(bp->b_bcount, DEV_BSIZE); |
573b5fae MH |
697 | pinfo = &sc->sc_info.si_label.d_partitions[sdpart(bp->b_dev)]; |
698 | if (bn < 0 || bn + sz > pinfo->p_size) { | |
699 | sz = pinfo->p_size - bn; | |
22d09b27 | 700 | if (sz == 0) { |
60f56dfc KM |
701 | bp->b_resid = bp->b_bcount; |
702 | goto done; | |
703 | } | |
22d09b27 KM |
704 | if (sz < 0) { |
705 | bp->b_error = EINVAL; | |
573b5fae | 706 | goto bad; |
22d09b27 KM |
707 | } |
708 | bp->b_bcount = dbtob(sz); | |
60f56dfc | 709 | } |
573b5fae MH |
710 | /* |
711 | * Check for write to write protected label | |
712 | */ | |
713 | if (bn + pinfo->p_offset <= LABELSECTOR && | |
714 | #if LABELSECTOR != 0 | |
715 | bn + pinfo->p_offset + sz > LABELSECTOR && | |
716 | #endif | |
717 | !(bp->b_flags & B_READ) && !(sc->sc_flags & SDF_WLABEL)) { | |
718 | bp->b_error = EROFS; | |
719 | goto bad; | |
720 | } | |
60f56dfc KM |
721 | /* |
722 | * Non-aligned or partial-block transfers handled specially. | |
723 | */ | |
724 | s = sc->sc_blksize - 1; | |
725 | if ((dbtob(bn) & s) || (bp->b_bcount & s)) { | |
726 | sdlblkstrat(bp, sc->sc_blksize); | |
727 | goto done; | |
728 | } | |
573b5fae | 729 | bp->b_cylin = (bn + pinfo->p_offset) >> sc->sc_bshift; |
60f56dfc KM |
730 | } |
731 | s = splbio(); | |
732 | disksort(dp, bp); | |
733 | if (dp->b_active == 0) { | |
734 | dp->b_active = 1; | |
735 | sdustart(unit); | |
736 | } | |
737 | splx(s); | |
738 | return; | |
573b5fae MH |
739 | bad: |
740 | bp->b_flags |= B_ERROR; | |
60f56dfc | 741 | done: |
22d09b27 | 742 | biodone(bp); |
60f56dfc KM |
743 | } |
744 | ||
745 | void | |
746 | sdustart(unit) | |
747 | register int unit; | |
748 | { | |
749 | if (scsireq(&sd_softc[unit].sc_dq)) | |
750 | sdstart(unit); | |
751 | } | |
752 | ||
761052c0 MK |
753 | /* |
754 | * Return: | |
755 | * 0 if not really an error | |
756 | * <0 if we should do a retry | |
757 | * >0 if a fatal error | |
758 | */ | |
22d09b27 | 759 | static int |
60f56dfc KM |
760 | sderror(unit, sc, hp, stat) |
761 | int unit, stat; | |
762 | register struct sd_softc *sc; | |
763 | register struct hp_device *hp; | |
764 | { | |
761052c0 | 765 | int cond = 1; |
22d09b27 | 766 | |
60f56dfc KM |
767 | sdsense[unit].status = stat; |
768 | if (stat & STS_CHECKCOND) { | |
769 | struct scsi_xsense *sp; | |
770 | ||
771 | scsi_request_sense(hp->hp_ctlr, hp->hp_slave, | |
772 | sc->sc_punit, sdsense[unit].sense, | |
773 | sizeof(sdsense[unit].sense)); | |
774 | sp = (struct scsi_xsense *)sdsense[unit].sense; | |
775 | printf("sd%d: scsi sense class %d, code %d", unit, | |
776 | sp->class, sp->code); | |
777 | if (sp->class == 7) { | |
778 | printf(", key %d", sp->key); | |
779 | if (sp->valid) | |
780 | printf(", blk %d", *(int *)&sp->info1); | |
761052c0 MK |
781 | switch (sp->key) { |
782 | /* no sense, try again */ | |
783 | case 0: | |
784 | cond = -1; | |
785 | break; | |
786 | /* recovered error, not a problem */ | |
787 | case 1: | |
788 | cond = 0; | |
789 | break; | |
573b5fae MH |
790 | /* possible media change */ |
791 | case 6: | |
792 | /* | |
793 | * For removable media, if we are doing the | |
794 | * first open (i.e. reading the label) go | |
795 | * ahead and retry, otherwise someone has | |
796 | * changed the media out from under us and | |
797 | * we should abort any further operations | |
798 | * until a close is done. | |
799 | */ | |
800 | if (sc->sc_flags & SDF_RMEDIA) { | |
801 | if (sc->sc_flags & SDF_OPENING) | |
802 | cond = -1; | |
803 | else | |
804 | sc->sc_flags |= SDF_ERROR; | |
805 | } | |
806 | break; | |
761052c0 | 807 | } |
60f56dfc KM |
808 | } |
809 | printf("\n"); | |
810 | } | |
761052c0 | 811 | return(cond); |
60f56dfc KM |
812 | } |
813 | ||
814 | static void | |
815 | sdfinish(unit, sc, bp) | |
816 | int unit; | |
817 | register struct sd_softc *sc; | |
818 | register struct buf *bp; | |
819 | { | |
9acfa6cd MH |
820 | register struct buf *dp = &sdtab[unit]; |
821 | ||
822 | dp->b_errcnt = 0; | |
823 | dp->b_actf = bp->b_actf; | |
60f56dfc | 824 | bp->b_resid = 0; |
22d09b27 | 825 | biodone(bp); |
60f56dfc | 826 | scsifree(&sc->sc_dq); |
9acfa6cd | 827 | if (dp->b_actf) |
60f56dfc | 828 | sdustart(unit); |
9acfa6cd MH |
829 | else { |
830 | dp->b_active = 0; | |
831 | if (sc->sc_flags & SDF_WANTED) { | |
832 | sc->sc_flags &= ~SDF_WANTED; | |
833 | wakeup((caddr_t)dp); | |
834 | } | |
835 | } | |
60f56dfc KM |
836 | } |
837 | ||
838 | void | |
839 | sdstart(unit) | |
840 | register int unit; | |
841 | { | |
842 | register struct sd_softc *sc = &sd_softc[unit]; | |
843 | register struct hp_device *hp = sc->sc_hd; | |
844 | ||
845 | /* | |
846 | * we have the SCSI bus -- in format mode, we may or may not need dma | |
847 | * so check now. | |
848 | */ | |
0fb33df5 | 849 | if (sc->sc_format_pid >= 0 && legal_cmds[sdcmd[unit].cdb[0]] > 0) { |
60f56dfc KM |
850 | register struct buf *bp = sdtab[unit].b_actf; |
851 | register int sts; | |
852 | ||
4bcb05ed MH |
853 | sdtab[unit].b_errcnt = 0; |
854 | while (1) { | |
855 | sts = scsi_immed_command(hp->hp_ctlr, hp->hp_slave, | |
856 | sc->sc_punit, &sdcmd[unit], | |
857 | bp->b_un.b_addr, bp->b_bcount, | |
858 | bp->b_flags & B_READ); | |
859 | sdsense[unit].status = sts; | |
860 | if ((sts & 0xfe) == 0 || | |
861 | (sts = sderror(unit, sc, hp, sts)) == 0) | |
862 | break; | |
863 | if (sts > 0 || sdtab[unit].b_errcnt++ >= SDRETRY) { | |
864 | bp->b_flags |= B_ERROR; | |
865 | bp->b_error = EIO; | |
866 | break; | |
867 | } | |
60f56dfc KM |
868 | } |
869 | sdfinish(unit, sc, bp); | |
870 | ||
871 | } else if (scsiustart(hp->hp_ctlr)) | |
872 | sdgo(unit); | |
873 | } | |
874 | ||
875 | void | |
876 | sdgo(unit) | |
877 | register int unit; | |
878 | { | |
879 | register struct sd_softc *sc = &sd_softc[unit]; | |
880 | register struct hp_device *hp = sc->sc_hd; | |
881 | register struct buf *bp = sdtab[unit].b_actf; | |
882 | register int pad; | |
883 | register struct scsi_fmt_cdb *cmd; | |
884 | ||
0fb33df5 | 885 | if (sc->sc_format_pid >= 0) { |
60f56dfc KM |
886 | cmd = &sdcmd[unit]; |
887 | pad = 0; | |
888 | } else { | |
4bcb05ed MH |
889 | /* |
890 | * Drive is in an error state, abort all operations | |
891 | */ | |
892 | if (sc->sc_flags & SDF_ERROR) { | |
893 | bp->b_flags |= B_ERROR; | |
894 | bp->b_error = EIO; | |
895 | sdfinish(unit, sc, bp); | |
896 | return; | |
897 | } | |
60f56dfc KM |
898 | cmd = bp->b_flags & B_READ? &sd_read_cmd : &sd_write_cmd; |
899 | *(int *)(&cmd->cdb[2]) = bp->b_cylin; | |
900 | pad = howmany(bp->b_bcount, sc->sc_blksize); | |
901 | *(u_short *)(&cmd->cdb[7]) = pad; | |
902 | pad = (bp->b_bcount & (sc->sc_blksize - 1)) != 0; | |
903 | #ifdef DEBUG | |
904 | if (pad) | |
905 | printf("sd%d: partial block xfer -- %x bytes\n", | |
906 | unit, bp->b_bcount); | |
907 | #endif | |
908 | sdstats[unit].sdtransfers++; | |
909 | } | |
573b5fae MH |
910 | #ifdef USELEDS |
911 | if (inledcontrol == 0) | |
912 | ledcontrol(0, 0, LED_DISK); | |
913 | #endif | |
60f56dfc KM |
914 | if (scsigo(hp->hp_ctlr, hp->hp_slave, sc->sc_punit, bp, cmd, pad) == 0) { |
915 | if (hp->hp_dk >= 0) { | |
916 | dk_busy |= 1 << hp->hp_dk; | |
917 | ++dk_seek[hp->hp_dk]; | |
918 | ++dk_xfer[hp->hp_dk]; | |
919 | dk_wds[hp->hp_dk] += bp->b_bcount >> 6; | |
920 | } | |
921 | return; | |
922 | } | |
923 | #ifdef DEBUG | |
924 | if (sddebug & SDB_ERROR) | |
925 | printf("sd%d: sdstart: %s adr %d blk %d len %d ecnt %d\n", | |
926 | unit, bp->b_flags & B_READ? "read" : "write", | |
927 | bp->b_un.b_addr, bp->b_cylin, bp->b_bcount, | |
928 | sdtab[unit].b_errcnt); | |
929 | #endif | |
930 | bp->b_flags |= B_ERROR; | |
931 | bp->b_error = EIO; | |
932 | sdfinish(unit, sc, bp); | |
933 | } | |
934 | ||
935 | void | |
936 | sdintr(unit, stat) | |
937 | register int unit; | |
938 | int stat; | |
939 | { | |
940 | register struct sd_softc *sc = &sd_softc[unit]; | |
941 | register struct buf *bp = sdtab[unit].b_actf; | |
942 | register struct hp_device *hp = sc->sc_hd; | |
761052c0 | 943 | int cond; |
60f56dfc KM |
944 | |
945 | if (bp == NULL) { | |
946 | printf("sd%d: bp == NULL\n", unit); | |
947 | return; | |
948 | } | |
949 | if (hp->hp_dk >= 0) | |
950 | dk_busy &=~ (1 << hp->hp_dk); | |
951 | if (stat) { | |
952 | #ifdef DEBUG | |
953 | if (sddebug & SDB_ERROR) | |
954 | printf("sd%d: sdintr: bad scsi status 0x%x\n", | |
955 | unit, stat); | |
956 | #endif | |
761052c0 MK |
957 | cond = sderror(unit, sc, hp, stat); |
958 | if (cond) { | |
959 | if (cond < 0 && sdtab[unit].b_errcnt++ < SDRETRY) { | |
ebe91f3c | 960 | #ifdef DEBUG |
761052c0 MK |
961 | if (sddebug & SDB_ERROR) |
962 | printf("sd%d: retry #%d\n", | |
963 | unit, sdtab[unit].b_errcnt); | |
ebe91f3c | 964 | #endif |
761052c0 MK |
965 | sdstart(unit); |
966 | return; | |
967 | } | |
968 | bp->b_flags |= B_ERROR; | |
969 | bp->b_error = EIO; | |
22d09b27 | 970 | } |
60f56dfc KM |
971 | } |
972 | sdfinish(unit, sc, bp); | |
973 | } | |
974 | ||
975 | int | |
88f29710 | 976 | sdread(dev, uio, flags) |
60f56dfc KM |
977 | dev_t dev; |
978 | struct uio *uio; | |
88f29710 | 979 | int flags; |
60f56dfc KM |
980 | { |
981 | register int unit = sdunit(dev); | |
982 | register int pid; | |
983 | ||
0fb33df5 | 984 | if ((pid = sd_softc[unit].sc_format_pid) >= 0 && |
88f29710 | 985 | pid != uio->uio_procp->p_pid) |
60f56dfc KM |
986 | return (EPERM); |
987 | ||
88f29710 | 988 | return (physio(sdstrategy, NULL, dev, B_READ, minphys, uio)); |
60f56dfc KM |
989 | } |
990 | ||
991 | int | |
88f29710 | 992 | sdwrite(dev, uio, flags) |
60f56dfc KM |
993 | dev_t dev; |
994 | struct uio *uio; | |
88f29710 | 995 | int flags; |
60f56dfc KM |
996 | { |
997 | register int unit = sdunit(dev); | |
998 | register int pid; | |
999 | ||
0fb33df5 | 1000 | if ((pid = sd_softc[unit].sc_format_pid) >= 0 && |
88f29710 | 1001 | pid != uio->uio_procp->p_pid) |
60f56dfc KM |
1002 | return (EPERM); |
1003 | ||
88f29710 | 1004 | return (physio(sdstrategy, NULL, dev, B_WRITE, minphys, uio)); |
60f56dfc KM |
1005 | } |
1006 | ||
1007 | int | |
88f29710 | 1008 | sdioctl(dev, cmd, data, flag, p) |
60f56dfc | 1009 | dev_t dev; |
fea890a2 | 1010 | u_long cmd; |
60f56dfc KM |
1011 | caddr_t data; |
1012 | int flag; | |
88f29710 | 1013 | struct proc *p; |
60f56dfc | 1014 | { |
573b5fae | 1015 | int unit = sdunit(dev); |
60f56dfc | 1016 | register struct sd_softc *sc = &sd_softc[unit]; |
573b5fae MH |
1017 | register struct disklabel *lp = &sc->sc_info.si_label; |
1018 | int error, flags; | |
60f56dfc KM |
1019 | |
1020 | switch (cmd) { | |
1021 | default: | |
1022 | return (EINVAL); | |
1023 | ||
573b5fae MH |
1024 | case DIOCGDINFO: |
1025 | *(struct disklabel *)data = *lp; | |
1026 | return (0); | |
1027 | ||
1028 | case DIOCGPART: | |
1029 | ((struct partinfo *)data)->disklab = lp; | |
1030 | ((struct partinfo *)data)->part = | |
1031 | &lp->d_partitions[sdpart(dev)]; | |
1032 | return (0); | |
1033 | ||
1034 | case DIOCWLABEL: | |
1035 | if ((flag & FWRITE) == 0) | |
1036 | return (EBADF); | |
1037 | if (*(int *)data) | |
1038 | sc->sc_flags |= SDF_WLABEL; | |
1039 | else | |
1040 | sc->sc_flags &= ~SDF_WLABEL; | |
1041 | return (0); | |
1042 | ||
1043 | case DIOCSDINFO: | |
1044 | if ((flag & FWRITE) == 0) | |
1045 | return (EBADF); | |
1046 | error = setdisklabel(lp, (struct disklabel *)data, | |
1047 | (sc->sc_flags & SDF_WLABEL) ? 0 | |
1048 | : sc->sc_info.si_open); | |
1049 | return (error); | |
1050 | ||
1051 | case DIOCWDINFO: | |
1052 | if ((flag & FWRITE) == 0) | |
1053 | return (EBADF); | |
1054 | error = setdisklabel(lp, (struct disklabel *)data, | |
1055 | (sc->sc_flags & SDF_WLABEL) ? 0 | |
1056 | : sc->sc_info.si_open); | |
1057 | if (error) | |
1058 | return (error); | |
1059 | flags = sc->sc_flags; | |
1060 | sc->sc_flags = SDF_ALIVE | SDF_WLABEL; | |
1061 | error = writedisklabel(sdlabdev(dev), sdstrategy, lp); | |
1062 | sc->sc_flags = flags; | |
1063 | return (error); | |
1064 | ||
60f56dfc KM |
1065 | case SDIOCSFORMAT: |
1066 | /* take this device into or out of "format" mode */ | |
88f29710 | 1067 | if (suser(p->p_ucred, &p->p_acflag)) |
60f56dfc KM |
1068 | return(EPERM); |
1069 | ||
1070 | if (*(int *)data) { | |
0fb33df5 | 1071 | if (sc->sc_format_pid >= 0) |
60f56dfc | 1072 | return (EPERM); |
88f29710 | 1073 | sc->sc_format_pid = p->p_pid; |
60f56dfc | 1074 | } else |
0fb33df5 | 1075 | sc->sc_format_pid = -1; |
60f56dfc KM |
1076 | return (0); |
1077 | ||
1078 | case SDIOCGFORMAT: | |
1079 | /* find out who has the device in format mode */ | |
1080 | *(int *)data = sc->sc_format_pid; | |
1081 | return (0); | |
1082 | ||
1083 | case SDIOCSCSICOMMAND: | |
1084 | /* | |
1085 | * Save what user gave us as SCSI cdb to use with next | |
1086 | * read or write to the char device. | |
1087 | */ | |
88f29710 | 1088 | if (sc->sc_format_pid != p->p_pid) |
60f56dfc KM |
1089 | return (EPERM); |
1090 | if (legal_cmds[((struct scsi_fmt_cdb *)data)->cdb[0]] == 0) | |
1091 | return (EINVAL); | |
1092 | bcopy(data, (caddr_t)&sdcmd[unit], sizeof(sdcmd[0])); | |
1093 | return (0); | |
1094 | ||
1095 | case SDIOCSENSE: | |
1096 | /* | |
1097 | * return the SCSI sense data saved after the last | |
1098 | * operation that completed with "check condition" status. | |
1099 | */ | |
1100 | bcopy((caddr_t)&sdsense[unit], data, sizeof(sdsense[0])); | |
1101 | return (0); | |
1102 | ||
1103 | } | |
1104 | /*NOTREACHED*/ | |
1105 | } | |
1106 | ||
1107 | int | |
1108 | sdsize(dev) | |
1109 | dev_t dev; | |
1110 | { | |
1111 | register int unit = sdunit(dev); | |
1112 | register struct sd_softc *sc = &sd_softc[unit]; | |
573b5fae | 1113 | int psize, didopen = 0; |
60f56dfc KM |
1114 | |
1115 | if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0) | |
1116 | return(-1); | |
1117 | ||
573b5fae MH |
1118 | /* |
1119 | * We get called very early on (via swapconf) | |
1120 | * without the device being open so we may need | |
1121 | * to handle it here. | |
1122 | */ | |
1123 | if (sc->sc_info.si_open == 0) { | |
1124 | if (sdopen(dev, FREAD|FWRITE, S_IFBLK, NULL)) | |
1125 | return(-1); | |
1126 | didopen = 1; | |
1127 | } | |
1128 | psize = sc->sc_info.si_label.d_partitions[sdpart(dev)].p_size; | |
1129 | if (didopen) | |
1130 | (void) sdclose(dev, FREAD|FWRITE, S_IFBLK, NULL); | |
1131 | return (psize); | |
60f56dfc KM |
1132 | } |
1133 | ||
60f56dfc KM |
1134 | /* |
1135 | * Non-interrupt driven, non-dma dump routine. | |
1136 | */ | |
1137 | int | |
1138 | sddump(dev) | |
1139 | dev_t dev; | |
1140 | { | |
1141 | int part = sdpart(dev); | |
1142 | int unit = sdunit(dev); | |
1143 | register struct sd_softc *sc = &sd_softc[unit]; | |
1144 | register struct hp_device *hp = sc->sc_hd; | |
573b5fae | 1145 | register struct partition *pinfo; |
60f56dfc KM |
1146 | register daddr_t baddr; |
1147 | register int maddr; | |
1148 | register int pages, i; | |
1149 | int stat; | |
0fb33df5 | 1150 | extern int lowram, dumpsize; |
60f56dfc | 1151 | |
60f56dfc KM |
1152 | /* is drive ok? */ |
1153 | if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0) | |
1154 | return (ENXIO); | |
573b5fae | 1155 | pinfo = &sc->sc_info.si_label.d_partitions[part]; |
60f56dfc | 1156 | /* dump parameters in range? */ |
573b5fae MH |
1157 | if (dumplo < 0 || dumplo >= pinfo->p_size || |
1158 | pinfo->p_fstype != FS_SWAP) | |
60f56dfc | 1159 | return (EINVAL); |
0fb33df5 | 1160 | pages = dumpsize; |
573b5fae MH |
1161 | if (dumplo + ctod(pages) > pinfo->p_size) |
1162 | pages = dtoc(pinfo->p_size - dumplo); | |
60f56dfc | 1163 | maddr = lowram; |
573b5fae | 1164 | baddr = dumplo + pinfo->p_offset; |
60f56dfc KM |
1165 | /* scsi bus idle? */ |
1166 | if (!scsireq(&sc->sc_dq)) { | |
1167 | scsireset(hp->hp_ctlr); | |
1168 | sdreset(sc, sc->sc_hd); | |
1169 | printf("[ drive %d reset ] ", unit); | |
1170 | } | |
1171 | for (i = 0; i < pages; i++) { | |
1172 | #define NPGMB (1024*1024/NBPG) | |
1173 | /* print out how many Mbs we have dumped */ | |
1174 | if (i && (i % NPGMB) == 0) | |
1175 | printf("%d ", i / NPGMB); | |
1176 | #undef NPBMG | |
7cf88bec | 1177 | pmap_enter(kernel_pmap, (vm_offset_t)vmmap, maddr, |
e0f6df7b | 1178 | VM_PROT_READ, TRUE); |
60f56dfc KM |
1179 | stat = scsi_tt_write(hp->hp_ctlr, hp->hp_slave, sc->sc_punit, |
1180 | vmmap, NBPG, baddr, sc->sc_bshift); | |
1181 | if (stat) { | |
1182 | printf("sddump: scsi write error 0x%x\n", stat); | |
1183 | return (EIO); | |
1184 | } | |
1185 | maddr += NBPG; | |
1186 | baddr += ctod(1); | |
1187 | } | |
1188 | return (0); | |
1189 | } | |
1190 | #endif |