Commit | Line | Data |
---|---|---|
15637ed4 RG |
1 | /* |
2 | * Written by Julian Elischer (julian@tfs.com) | |
3 | * for TRW Financial Systems for use under the MACH(2.5) operating system. | |
4 | * | |
5 | * TRW Financial Systems, in accordance with their agreement with Carnegie | |
6 | * Mellon University, makes this software available to CMU to distribute | |
7 | * or use in any manner that they see fit as long as this message is kept with | |
8 | * the software. For this reason TFS also grants any other persons or | |
9 | * organisations permission to use or modify this software. | |
10 | * | |
11 | * TFS supplies this software to be publicly redistributed | |
12 | * on the understanding that TFS is not responsible for the correct | |
13 | * functioning of this software in any circumstances. | |
14 | * | |
15637ed4 RG |
15 | * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 |
16 | * | |
62d80b5a | 17 | * $Id: cd.c,v 1.8 1993/09/09 07:18:52 rgrimes Exp $ |
15637ed4 RG |
18 | */ |
19 | ||
20 | #define SPLCD splbio | |
21 | #define ESUCCESS 0 | |
22 | #include <cd.h> | |
23 | #include <sys/types.h> | |
24 | #include <sys/param.h> | |
25 | #include <sys/dkbad.h> | |
26 | #include <sys/systm.h> | |
27 | #include <sys/conf.h> | |
28 | #include <sys/file.h> | |
29 | #include <sys/stat.h> | |
30 | #include <sys/ioctl.h> | |
31 | #include <sys/buf.h> | |
32 | #include <sys/uio.h> | |
33 | #include <sys/malloc.h> | |
34 | #include <sys/cdio.h> | |
35 | ||
36 | #include <sys/errno.h> | |
37 | #include <sys/disklabel.h> | |
38 | #include <scsi/scsi_all.h> | |
39 | #include <scsi/scsi_cd.h> | |
40 | #include <scsi/scsi_disk.h> /* rw_big and start_stop come from there */ | |
41 | #include <scsi/scsiconf.h> | |
42 | ||
43 | long int cdstrats,cdqueues; | |
44 | ||
45 | ||
46 | #include <ddb.h> | |
47 | #if NDDB > 0 | |
48 | int Debugger(); | |
49 | #else NDDB > 0 | |
50 | #define Debugger() | |
51 | #endif NDDB > 0 | |
52 | ||
53 | ||
54 | #define PAGESIZ 4096 | |
55 | #define SECSIZE 2048 /* XXX */ /* default only */ | |
56 | #define CDOUTSTANDING 2 | |
57 | #define CDQSIZE 4 | |
58 | #define CD_RETRIES 4 | |
59 | ||
60 | #define UNITSHIFT 3 | |
61 | #define PARTITION(z) (minor(z) & 0x07) | |
62 | #define RAW_PART 3 | |
63 | #define UNIT(z) ( (minor(z) >> UNITSHIFT) ) | |
64 | ||
65 | ||
66 | extern int hz; | |
67 | int cd_done(); | |
68 | int cdstrategy(); | |
69 | int cd_debug = 0; | |
70 | ||
15637ed4 RG |
71 | |
72 | struct cd_data | |
73 | { | |
74 | int flags; | |
75 | #define CDVALID 0x02 /* PARAMS LOADED */ | |
76 | #define CDINIT 0x04 /* device has been init'd */ | |
77 | #define CDWAIT 0x08 /* device has someone waiting */ | |
78 | #define CDHAVELABEL 0x10 /* have read the label */ | |
79 | struct scsi_switch *sc_sw; /* address of scsi low level switch */ | |
80 | int ctlr; /* so they know which one we want */ | |
81 | int targ; /* our scsi target ID */ | |
82 | int lu; /* out scsi lu */ | |
83 | int cmdscount; /* cmds allowed outstanding by board*/ | |
84 | struct cd_parms | |
85 | { | |
86 | int blksize; | |
87 | u_long disksize; /* total number sectors */ | |
88 | }params; | |
89 | struct disklabel disklabel; | |
90 | int partflags[MAXPARTITIONS]; /* per partition flags */ | |
91 | #define CDOPEN 0x01 | |
92 | int openparts; /* one bit for each open partition */ | |
4f6ede5d RG |
93 | int xfer_block_wait; |
94 | struct scsi_xfer *free_xfer; | |
95 | struct scsi_xfer scsi_xfer[CDOUTSTANDING]; /* XXX */ | |
96 | struct buf buf_queue; | |
97 | }; | |
15637ed4 RG |
98 | |
99 | #define CD_STOP 0 | |
100 | #define CD_START 1 | |
101 | #define CD_EJECT -2 | |
102 | ||
4f6ede5d RG |
103 | struct cd_driver |
104 | { | |
105 | int size; | |
106 | struct cd_data **cd_data; | |
107 | }*cd_driver; | |
15637ed4 RG |
108 | |
109 | static int next_cd_unit = 0; | |
110 | /***********************************************************************\ | |
111 | * The routine called by the low level scsi routine when it discovers * | |
112 | * A device suitable for this driver * | |
113 | \***********************************************************************/ | |
114 | int cdattach(ctlr,targ,lu,scsi_switch) | |
115 | struct scsi_switch *scsi_switch; | |
116 | { | |
4f6ede5d RG |
117 | int unit,i; |
118 | unsigned char *tbl; | |
119 | struct cd_data *cd, **cdrealloc; | |
120 | struct cd_parms *dp; | |
15637ed4 | 121 | |
de4fe9fb | 122 | #ifdef CDDEBUG |
15637ed4 | 123 | if(scsi_debug & PRINTROUTINES) printf("cdattach: "); |
de4fe9fb | 124 | #endif /*CDDEBUG*/ |
15637ed4 | 125 | /*******************************************************\ |
4f6ede5d RG |
126 | * Check if we have resources allocated yet, if not * |
127 | * allocate and initialize them * | |
128 | \*******************************************************/ | |
129 | if (next_cd_unit == 0) | |
130 | { | |
131 | cd_driver = | |
132 | malloc(sizeof(struct cd_driver),M_DEVBUF,M_NOWAIT); | |
133 | if(!cd_driver) | |
134 | { | |
135 | printf("cd%d: malloc failed for cd_driver\n",unit); | |
136 | return(0); | |
137 | } | |
138 | bzero(cd_driver,sizeof(cd_driver)); | |
139 | cd_driver->size = 0; | |
140 | } | |
141 | /*******************************************************\ | |
142 | * allocate the resources for another drive * | |
143 | * if we have already allocate a cd_data pointer we must * | |
144 | * copy the old pointers into a new region that is * | |
145 | * larger and release the old region, aka realloc * | |
15637ed4 | 146 | \*******************************************************/ |
de4fe9fb | 147 | unit = next_cd_unit++; |
4f6ede5d RG |
148 | /* XXX |
149 | * This if will always be true for now, but future code may | |
150 | * preallocate more units to reduce overhead. This would be | |
151 | * done by changing the malloc to be (next_cd_unit * x) and | |
152 | * the cd_driver->size++ to be +x | |
153 | */ | |
154 | if(unit >= cd_driver->size) | |
15637ed4 | 155 | { |
4f6ede5d RG |
156 | cdrealloc = |
157 | malloc(sizeof(cd_driver->cd_data) * next_cd_unit, | |
158 | M_DEVBUF,M_NOWAIT); | |
159 | if(!cdrealloc) | |
160 | { | |
161 | printf("cd%d: malloc failed for cdrealloc\n",unit); | |
162 | return(0); | |
163 | } | |
164 | /* Make sure we have something to copy before we copy it */ | |
62d80b5a | 165 | bzero(cdrealloc,sizeof(cd_driver->cd_data) * next_cd_unit); |
4f6ede5d RG |
166 | if(cd_driver->size) |
167 | { | |
168 | bcopy(cd_driver->cd_data,cdrealloc, | |
169 | sizeof(cd_driver->cd_data) * cd_driver->size); | |
170 | free(cd_driver->cd_data,M_DEVBUF); | |
171 | } | |
172 | cd_driver->cd_data = cdrealloc; | |
173 | cd_driver->cd_data[unit] = NULL; | |
174 | cd_driver->size++; | |
15637ed4 | 175 | } |
4f6ede5d | 176 | if(cd_driver->cd_data[unit]) |
de4fe9fb RG |
177 | { |
178 | printf("cd%d: Already has storage!\n",unit); | |
179 | return(0); | |
180 | } | |
4f6ede5d RG |
181 | /*******************************************************\ |
182 | * allocate the per drive data area * | |
183 | \*******************************************************/ | |
184 | cd = cd_driver->cd_data[unit] = | |
185 | malloc(sizeof(struct cd_data),M_DEVBUF,M_NOWAIT); | |
de4fe9fb RG |
186 | if(!cd) |
187 | { | |
4f6ede5d | 188 | printf("cd%d: malloc failed for cd_data\n",unit); |
de4fe9fb RG |
189 | return(0); |
190 | } | |
62d80b5a | 191 | bzero(cd,sizeof(struct cd_data)); |
d4284689 | 192 | dp = &(cd->params); |
15637ed4 RG |
193 | /*******************************************************\ |
194 | * Store information needed to contact our base driver * | |
195 | \*******************************************************/ | |
196 | cd->sc_sw = scsi_switch; | |
197 | cd->ctlr = ctlr; | |
198 | cd->targ = targ; | |
199 | cd->lu = lu; | |
200 | cd->cmdscount = CDOUTSTANDING; /* XXX (ask the board) */ | |
201 | ||
15637ed4 RG |
202 | i = cd->cmdscount; |
203 | while(i-- ) | |
204 | { | |
4f6ede5d RG |
205 | cd->scsi_xfer[i].next = cd->free_xfer; |
206 | cd->free_xfer = &cd->scsi_xfer[i]; | |
15637ed4 RG |
207 | } |
208 | /*******************************************************\ | |
209 | * Use the subdriver to request information regarding * | |
210 | * the drive. We cannot use interrupts yet, so the * | |
211 | * request must specify this. * | |
212 | \*******************************************************/ | |
213 | cd_get_parms(unit, SCSI_NOSLEEP | SCSI_NOMASK); | |
214 | if(dp->disksize) | |
215 | { | |
98639498 | 216 | printf("cd%d: cd present\n", unit); |
15637ed4 RG |
217 | } |
218 | else | |
219 | { | |
98639498 | 220 | printf("cd%d: drive empty\n", unit); |
15637ed4 RG |
221 | } |
222 | cd->flags |= CDINIT; | |
223 | return; | |
15637ed4 RG |
224 | } |
225 | ||
15637ed4 RG |
226 | /*******************************************************\ |
227 | * open the device. Make sure the partition info * | |
228 | * is a up-to-date as can be. * | |
229 | \*******************************************************/ | |
230 | cdopen(dev) | |
231 | { | |
232 | int errcode = 0; | |
233 | int unit, part; | |
234 | struct cd_parms cd_parms; | |
de4fe9fb | 235 | struct cd_data *cd; |
15637ed4 RG |
236 | |
237 | unit = UNIT(dev); | |
238 | part = PARTITION(dev); | |
de4fe9fb RG |
239 | |
240 | #ifdef CDDEBUG | |
15637ed4 RG |
241 | if(scsi_debug & (PRINTROUTINES | TRACEOPENS)) |
242 | printf("cdopen: dev=0x%x (unit %d (of %d),partition %d)\n" | |
4f6ede5d | 243 | ,dev,unit,cd_driver->size,part); |
de4fe9fb | 244 | #endif /*CDDEBUG*/ |
15637ed4 RG |
245 | /*******************************************************\ |
246 | * Check the unit is legal * | |
247 | \*******************************************************/ | |
4f6ede5d | 248 | if ( unit >= cd_driver->size ) |
15637ed4 RG |
249 | { |
250 | return(ENXIO); | |
251 | } | |
4f6ede5d | 252 | cd = cd_driver->cd_data[unit]; |
15637ed4 | 253 | /*******************************************************\ |
de4fe9fb | 254 | * Make sure the device has been initialised * |
15637ed4 | 255 | \*******************************************************/ |
de4fe9fb | 256 | if ((cd == NULL) || (!(cd->flags & CDINIT))) |
15637ed4 RG |
257 | return(ENXIO); |
258 | ||
259 | /*******************************************************\ | |
260 | * If it's been invalidated, and not everybody has * | |
261 | * closed it then forbid re-entry. * | |
262 | * (may have changed media) * | |
263 | \*******************************************************/ | |
264 | if ((! (cd->flags & CDVALID)) | |
265 | && ( cd->openparts)) | |
266 | return(ENXIO); | |
267 | /*******************************************************\ | |
268 | * Check that it is still responding and ok. * | |
269 | * if the media has been changed this will result in a * | |
270 | * "unit attention" error which the error code will * | |
271 | * disregard because the CDVALID flag is not yet set * | |
272 | \*******************************************************/ | |
273 | if (cd_req_sense(unit, SCSI_SILENT) != 0) { | |
de4fe9fb | 274 | #ifdef CDDEBUG |
15637ed4 RG |
275 | if(scsi_debug & TRACEOPENS) |
276 | printf("not reponding\n"); | |
de4fe9fb | 277 | #endif /*CDDEBUG*/ |
15637ed4 RG |
278 | return(ENXIO); |
279 | } | |
de4fe9fb | 280 | #ifdef CDDEBUG |
15637ed4 RG |
281 | if(scsi_debug & TRACEOPENS) |
282 | printf("Device present\n"); | |
de4fe9fb | 283 | #endif /*CDDEBUG*/ |
15637ed4 RG |
284 | /*******************************************************\ |
285 | * In case it is a funny one, tell it to start * | |
286 | * not needed for hard drives * | |
287 | \*******************************************************/ | |
288 | cd_start_unit(unit,part,CD_START); | |
289 | cd_prevent_unit(unit,PR_PREVENT,SCSI_SILENT); | |
de4fe9fb | 290 | #ifdef CDDEBUG |
15637ed4 RG |
291 | if(scsi_debug & TRACEOPENS) |
292 | printf("started "); | |
de4fe9fb | 293 | #endif /*CDDEBUG*/ |
15637ed4 RG |
294 | /*******************************************************\ |
295 | * Load the physical device parameters * | |
296 | \*******************************************************/ | |
297 | cd_get_parms(unit, 0); | |
de4fe9fb | 298 | #ifdef CDDEBUG |
15637ed4 RG |
299 | if(scsi_debug & TRACEOPENS) |
300 | printf("Params loaded "); | |
de4fe9fb | 301 | #endif /*CDDEBUG*/ |
15637ed4 RG |
302 | /*******************************************************\ |
303 | * Load the partition info if not already loaded * | |
304 | \*******************************************************/ | |
305 | cdgetdisklabel(unit); | |
de4fe9fb | 306 | #ifdef CDDEBUG |
15637ed4 RG |
307 | if(scsi_debug & TRACEOPENS) |
308 | printf("Disklabel fabricated "); | |
de4fe9fb | 309 | #endif /*CDDEBUG*/ |
15637ed4 RG |
310 | /*******************************************************\ |
311 | * Check the partition is legal * | |
312 | \*******************************************************/ | |
313 | if (( part >= cd->disklabel.d_npartitions ) | |
314 | && (part != RAW_PART)) | |
315 | { | |
de4fe9fb | 316 | #ifdef CDDEBUG |
15637ed4 RG |
317 | if(scsi_debug & TRACEOPENS) |
318 | printf("partition %d > %d\n",part | |
319 | ,cd->disklabel.d_npartitions); | |
de4fe9fb | 320 | #endif /*CDDEBUG*/ |
15637ed4 RG |
321 | cd_prevent_unit(unit,PR_ALLOW,SCSI_SILENT); |
322 | return(ENXIO); | |
323 | } | |
324 | /*******************************************************\ | |
325 | * Check that the partition exists * | |
326 | \*******************************************************/ | |
327 | if (( cd->disklabel.d_partitions[part].p_fstype != FS_UNUSED ) | |
328 | || (part == RAW_PART)) | |
329 | { | |
330 | cd->partflags[part] |= CDOPEN; | |
331 | cd->openparts |= (1 << part); | |
de4fe9fb | 332 | #ifdef CDDEBUG |
15637ed4 RG |
333 | if(scsi_debug & TRACEOPENS) |
334 | printf("open complete\n"); | |
de4fe9fb | 335 | #endif /*CDDEBUG*/ |
15637ed4 RG |
336 | cd->flags |= CDVALID; |
337 | } | |
338 | else | |
339 | { | |
de4fe9fb | 340 | #ifdef CDDEBUG |
15637ed4 RG |
341 | if(scsi_debug & TRACEOPENS) |
342 | printf("part %d type UNUSED\n",part); | |
de4fe9fb | 343 | #endif /*CDDEBUG*/ |
15637ed4 RG |
344 | cd_prevent_unit(unit,PR_ALLOW,SCSI_SILENT); |
345 | return(ENXIO); | |
346 | } | |
347 | return(0); | |
348 | } | |
349 | ||
350 | /*******************************************************\ | |
351 | * Get ownership of a scsi_xfer structure * | |
352 | * If need be, sleep on it, until it comes free * | |
353 | \*******************************************************/ | |
354 | struct scsi_xfer *cd_get_xs(unit,flags) | |
355 | int flags; | |
356 | int unit; | |
357 | { | |
358 | struct scsi_xfer *xs; | |
4f6ede5d | 359 | struct cd_data *cd; |
15637ed4 RG |
360 | int s; |
361 | ||
4f6ede5d | 362 | cd = cd_driver->cd_data[unit]; |
15637ed4 RG |
363 | if(flags & (SCSI_NOSLEEP | SCSI_NOMASK)) |
364 | { | |
4f6ede5d | 365 | if (xs = cd->free_xfer) |
15637ed4 | 366 | { |
4f6ede5d | 367 | cd->free_xfer = xs->next; |
15637ed4 RG |
368 | xs->flags = 0; |
369 | } | |
370 | } | |
371 | else | |
372 | { | |
373 | s = SPLCD(); | |
4f6ede5d | 374 | while (!(xs = cd->free_xfer)) |
15637ed4 | 375 | { |
4f6ede5d RG |
376 | cd->xfer_block_wait++; /* someone waiting! */ |
377 | sleep((caddr_t)&cd->free_xfer, PRIBIO+1); | |
378 | cd->xfer_block_wait--; | |
15637ed4 | 379 | } |
4f6ede5d | 380 | cd->free_xfer = xs->next; |
15637ed4 RG |
381 | splx(s); |
382 | xs->flags = 0; | |
383 | } | |
384 | return(xs); | |
385 | } | |
386 | ||
387 | /*******************************************************\ | |
388 | * Free a scsi_xfer, wake processes waiting for it * | |
389 | \*******************************************************/ | |
390 | cd_free_xs(unit,xs,flags) | |
391 | struct scsi_xfer *xs; | |
392 | int unit; | |
393 | int flags; | |
394 | { | |
4f6ede5d | 395 | struct cd_data *cd; |
15637ed4 RG |
396 | int s; |
397 | ||
4f6ede5d | 398 | cd = cd_driver->cd_data[unit]; |
15637ed4 RG |
399 | if(flags & SCSI_NOMASK) |
400 | { | |
4f6ede5d | 401 | if (cd->xfer_block_wait) |
15637ed4 | 402 | { |
98639498 | 403 | printf("cd%d: doing a wakeup from NOMASK mode\n", unit); |
4f6ede5d | 404 | wakeup((caddr_t)&cd->free_xfer); |
15637ed4 | 405 | } |
4f6ede5d RG |
406 | xs->next = cd->free_xfer; |
407 | cd->free_xfer = xs; | |
15637ed4 RG |
408 | } |
409 | else | |
410 | { | |
411 | s = SPLCD(); | |
4f6ede5d RG |
412 | if (cd->xfer_block_wait) |
413 | wakeup((caddr_t)&cd->free_xfer); | |
414 | xs->next = cd->free_xfer; | |
415 | cd->free_xfer = xs; | |
15637ed4 RG |
416 | splx(s); |
417 | } | |
418 | } | |
419 | ||
420 | /*******************************************************\ | |
421 | * trim the size of the transfer if needed, * | |
422 | * called by physio * | |
423 | * basically the smaller of our max and the scsi driver's* | |
424 | * minphys (note we have no max ourselves) * | |
425 | \*******************************************************/ | |
426 | /* Trim buffer length if buffer-size is bigger than page size */ | |
427 | void cdminphys(bp) | |
428 | struct buf *bp; | |
429 | { | |
4f6ede5d | 430 | (*(cd_driver->cd_data[UNIT(bp->b_dev)]->sc_sw->scsi_minphys))(bp); |
15637ed4 RG |
431 | } |
432 | ||
433 | /*******************************************************\ | |
434 | * Actually translate the requested transfer into * | |
435 | * one the physical driver can understand * | |
436 | * The transfer is described by a buf and will include * | |
437 | * only one physical transfer. * | |
438 | \*******************************************************/ | |
439 | ||
440 | int cdstrategy(bp) | |
441 | struct buf *bp; | |
442 | { | |
443 | struct buf *dp; | |
444 | unsigned int opri; | |
de4fe9fb | 445 | struct cd_data *cd; |
15637ed4 RG |
446 | int unit; |
447 | ||
448 | cdstrats++; | |
449 | unit = UNIT((bp->b_dev)); | |
4f6ede5d | 450 | cd = cd_driver->cd_data[unit]; |
de4fe9fb | 451 | #ifdef CDDEBUG |
15637ed4 RG |
452 | if(scsi_debug & PRINTROUTINES) printf("\ncdstrategy "); |
453 | if(scsi_debug & SHOWREQUESTS) printf("cd%d: %d bytes @ blk%d\n", | |
454 | unit,bp->b_bcount,bp->b_blkno); | |
de4fe9fb | 455 | #endif /*CDDEBUG*/ |
15637ed4 RG |
456 | cdminphys(bp); |
457 | /*******************************************************\ | |
458 | * If the device has been made invalid, error out * | |
459 | * maybe the media changed * | |
460 | \*******************************************************/ | |
461 | if(!(cd->flags & CDVALID)) | |
462 | { | |
463 | bp->b_error = EIO; | |
464 | goto bad; | |
465 | } | |
466 | /*******************************************************\ | |
467 | * can't ever write to a CD * | |
468 | \*******************************************************/ | |
469 | if ((bp->b_flags & B_READ) == 0) { | |
470 | bp->b_error = EROFS; | |
471 | goto bad; | |
472 | } | |
473 | /*******************************************************\ | |
474 | * If it's a null transfer, return immediatly * | |
475 | \*******************************************************/ | |
476 | if (bp->b_bcount == 0) { | |
477 | goto done; | |
478 | } | |
479 | ||
480 | /*******************************************************\ | |
481 | * Decide which unit and partition we are talking about * | |
482 | \*******************************************************/ | |
483 | if(PARTITION(bp->b_dev) != RAW_PART) | |
484 | { | |
485 | if (!(cd->flags & CDHAVELABEL)) | |
486 | { | |
487 | bp->b_error = EIO; | |
488 | goto bad; | |
489 | } | |
490 | /* | |
491 | * do bounds checking, adjust transfer. if error, process. | |
492 | * if end of partition, just return | |
493 | */ | |
494 | if (bounds_check_with_label(bp,&cd->disklabel,1) <= 0) | |
495 | goto done; | |
496 | /* otherwise, process transfer request */ | |
497 | } | |
498 | ||
499 | opri = SPLCD(); | |
4f6ede5d | 500 | dp = &cd->buf_queue; |
15637ed4 RG |
501 | |
502 | /*******************************************************\ | |
503 | * Place it in the queue of disk activities for this disk* | |
504 | \*******************************************************/ | |
505 | disksort(dp, bp); | |
506 | ||
507 | /*******************************************************\ | |
508 | * Tell the device to get going on the transfer if it's * | |
509 | * not doing anything, otherwise just wait for completion* | |
510 | \*******************************************************/ | |
511 | cdstart(unit); | |
512 | ||
513 | splx(opri); | |
514 | return; | |
515 | bad: | |
516 | bp->b_flags |= B_ERROR; | |
517 | done: | |
518 | ||
519 | /*******************************************************\ | |
520 | * Correctly set the buf to indicate a completed xfer * | |
521 | \*******************************************************/ | |
522 | bp->b_resid = bp->b_bcount; | |
523 | biodone(bp); | |
524 | return; | |
525 | } | |
526 | ||
527 | /***************************************************************\ | |
528 | * cdstart looks to see if there is a buf waiting for the device * | |
529 | * and that the device is not already busy. If both are true, * | |
530 | * It deques the buf and creates a scsi command to perform the * | |
531 | * transfer in the buf. The transfer request will call cd_done * | |
532 | * on completion, which will in turn call this routine again * | |
533 | * so that the next queued transfer is performed. * | |
534 | * The bufs are queued by the strategy routine (cdstrategy) * | |
535 | * * | |
536 | * This routine is also called after other non-queued requests * | |
537 | * have been made of the scsi driver, to ensure that the queue * | |
538 | * continues to be drained. * | |
539 | * * | |
540 | * must be called at the correct (highish) spl level * | |
541 | \***************************************************************/ | |
542 | /* cdstart() is called at SPLCD from cdstrategy and cd_done*/ | |
543 | cdstart(unit) | |
544 | int unit; | |
545 | { | |
546 | register struct buf *bp = 0; | |
547 | register struct buf *dp; | |
548 | struct scsi_xfer *xs; | |
549 | struct scsi_rw_big cmd; | |
550 | int blkno, nblk; | |
4f6ede5d | 551 | struct cd_data *cd; |
15637ed4 RG |
552 | struct partition *p ; |
553 | ||
de4fe9fb | 554 | #ifdef CDDEBUG |
15637ed4 | 555 | if(scsi_debug & PRINTROUTINES) printf("cdstart%d ",unit); |
de4fe9fb | 556 | #endif /*CDDEBUG*/ |
4f6ede5d | 557 | cd = cd_driver->cd_data[unit]; |
15637ed4 RG |
558 | /*******************************************************\ |
559 | * See if there is a buf to do and we are not already * | |
560 | * doing one * | |
561 | \*******************************************************/ | |
4f6ede5d | 562 | if(!cd->free_xfer) |
15637ed4 RG |
563 | { |
564 | return; /* none for us, unit already underway */ | |
565 | } | |
566 | ||
4f6ede5d | 567 | if(cd->xfer_block_wait) /* there is one, but a special waits */ |
15637ed4 RG |
568 | { |
569 | return; /* give the special that's waiting a chance to run */ | |
570 | } | |
571 | ||
572 | ||
4f6ede5d | 573 | dp = &cd->buf_queue; |
15637ed4 RG |
574 | if ((bp = dp->b_actf) != NULL) /* yes, an assign */ |
575 | { | |
576 | dp->b_actf = bp->av_forw; | |
577 | } | |
578 | else | |
579 | { | |
580 | return; | |
581 | } | |
582 | ||
583 | xs=cd_get_xs(unit,0); /* ok we can grab it */ | |
584 | xs->flags = INUSE; /* Now ours */ | |
585 | /***************************************************************\ | |
586 | * Should reject all queued entries if CDVALID is not true * | |
587 | \***************************************************************/ | |
588 | if(!(cd->flags & CDVALID)) | |
589 | { | |
590 | goto bad; /* no I/O.. media changed or something */ | |
591 | } | |
592 | ||
593 | /*******************************************************\ | |
594 | * We have a buf, now we should move the data into * | |
595 | * a scsi_xfer definition and try start it * | |
596 | \*******************************************************/ | |
597 | /*******************************************************\ | |
598 | * First, translate the block to absolute * | |
599 | * and put it in terms of the logical blocksize of the * | |
600 | * device.. * | |
601 | \*******************************************************/ | |
602 | p = cd->disklabel.d_partitions + PARTITION(bp->b_dev); | |
603 | blkno = ((bp->b_blkno / (cd->params.blksize/512)) + p->p_offset); | |
604 | nblk = (bp->b_bcount + (cd->params.blksize - 1)) / (cd->params.blksize); | |
605 | ||
606 | /*******************************************************\ | |
607 | * Fill out the scsi command * | |
608 | \*******************************************************/ | |
609 | bzero(&cmd, sizeof(cmd)); | |
610 | cmd.op_code = READ_BIG; | |
611 | cmd.addr_3 = (blkno & 0xff000000) >> 24; | |
612 | cmd.addr_2 = (blkno & 0xff0000) >> 16; | |
613 | cmd.addr_1 = (blkno & 0xff00) >> 8; | |
614 | cmd.addr_0 = blkno & 0xff; | |
615 | cmd.length2 = (nblk & 0xff00) >> 8; | |
616 | cmd.length1 = (nblk & 0xff); | |
617 | /*******************************************************\ | |
618 | * Fill out the scsi_xfer structure * | |
619 | * Note: we cannot sleep as we may be an interrupt * | |
620 | \*******************************************************/ | |
621 | xs->flags |= SCSI_NOSLEEP; | |
622 | xs->adapter = cd->ctlr; | |
623 | xs->targ = cd->targ; | |
624 | xs->lu = cd->lu; | |
625 | xs->retries = CD_RETRIES; | |
626 | xs->timeout = 10000;/* 10000 millisecs for a disk !*/ | |
627 | xs->cmd = (struct scsi_generic *)&cmd; | |
628 | xs->cmdlen = sizeof(cmd); | |
629 | xs->resid = bp->b_bcount; | |
630 | xs->when_done = cd_done; | |
631 | xs->done_arg = unit; | |
632 | xs->done_arg2 = (int)xs; | |
633 | xs->error = XS_NOERROR; | |
634 | xs->bp = bp; | |
635 | xs->data = (u_char *)bp->b_un.b_addr; | |
636 | xs->datalen = bp->b_bcount; | |
637 | ||
638 | /*******************************************************\ | |
639 | * Pass all this info to the scsi driver. * | |
640 | \*******************************************************/ | |
641 | if ( (*(cd->sc_sw->scsi_cmd))(xs) != SUCCESSFULLY_QUEUED) | |
642 | { | |
643 | printf("cd%d: oops not queued",unit); | |
644 | goto bad; | |
645 | } | |
646 | cdqueues++; | |
647 | return; | |
648 | bad: xs->error = XS_DRIVER_STUFFUP; | |
649 | cd_done(unit,xs); | |
650 | } | |
651 | ||
652 | /*******************************************************\ | |
653 | * This routine is called by the scsi interrupt when * | |
654 | * the transfer is complete. (or failed) * | |
655 | \*******************************************************/ | |
656 | int cd_done(unit,xs) | |
657 | int unit; | |
658 | struct scsi_xfer *xs; | |
659 | { | |
660 | struct buf *bp; | |
661 | int retval; | |
4f6ede5d | 662 | struct cd_data *cd; |
15637ed4 | 663 | |
de4fe9fb | 664 | #ifdef CDDEBUG |
15637ed4 | 665 | if(scsi_debug & PRINTROUTINES) printf("cd_done%d ",unit); |
de4fe9fb | 666 | #endif /*CDDEBUG*/ |
4f6ede5d | 667 | cd = cd_driver->cd_data[unit]; |
15637ed4 RG |
668 | if (! (xs->flags & INUSE)) /* paranoia always pays off */ |
669 | panic("scsi_xfer not in use!"); | |
670 | if(bp = xs->bp) | |
671 | { | |
672 | switch(xs->error) | |
673 | { | |
674 | case XS_NOERROR: | |
675 | bp->b_error = 0; | |
676 | bp->b_resid = 0; | |
677 | break; | |
678 | ||
679 | case XS_SENSE: | |
680 | retval = (cd_interpret_sense(unit,xs)); | |
681 | if(retval) | |
682 | { | |
683 | bp->b_flags |= B_ERROR; | |
684 | bp->b_error = retval; | |
685 | } | |
686 | break; | |
687 | ||
688 | case XS_TIMEOUT: | |
689 | printf("cd%d timeout\n",unit); | |
690 | ||
691 | case XS_BUSY: | |
692 | /***********************************\ | |
693 | * Just resubmit it straight back to * | |
694 | * the SCSI driver to try it again * | |
695 | \***********************************/ | |
696 | if(xs->retries--) | |
697 | { | |
698 | xs->error = XS_NOERROR; | |
699 | xs->flags &= ~ITSDONE; | |
4f6ede5d | 700 | if ((*(cd->sc_sw->scsi_cmd))(xs) |
15637ed4 RG |
701 | == SUCCESSFULLY_QUEUED) |
702 | { /* shhh! don't wake the job, ok? */ | |
703 | /* don't tell cdstart either, */ | |
704 | return; | |
705 | } | |
706 | /* xs->error is set by the scsi driver */ | |
707 | } /* Fall through */ | |
708 | ||
709 | case XS_DRIVER_STUFFUP: | |
710 | bp->b_flags |= B_ERROR; | |
711 | bp->b_error = EIO; | |
712 | break; | |
713 | default: | |
714 | printf("cd%d: unknown error category from scsi driver\n" | |
715 | ,unit); | |
716 | } | |
717 | biodone(bp); | |
718 | cd_free_xs(unit,xs,0); | |
719 | cdstart(unit); /* If there's anything waiting.. do it */ | |
720 | } | |
721 | else /* special has finished */ | |
722 | { | |
723 | wakeup(xs); | |
724 | } | |
725 | } | |
726 | /*******************************************************\ | |
727 | * Perform special action on behalf of the user * | |
728 | * Knows about the internals of this device * | |
729 | \*******************************************************/ | |
730 | cdioctl(dev_t dev, int cmd, caddr_t addr, int flag) | |
731 | { | |
732 | int error = 0; | |
733 | unsigned int opri; | |
734 | unsigned char unit, part; | |
735 | register struct cd_data *cd; | |
736 | ||
737 | ||
738 | /*******************************************************\ | |
739 | * Find the device that the user is talking about * | |
740 | \*******************************************************/ | |
741 | unit = UNIT(dev); | |
742 | part = PARTITION(dev); | |
4f6ede5d | 743 | cd = cd_driver->cd_data[unit]; |
de4fe9fb | 744 | #ifdef CDDEBUG |
15637ed4 | 745 | if(scsi_debug & PRINTROUTINES) printf("cdioctl%d ",unit); |
de4fe9fb | 746 | #endif /*CDDEBUG*/ |
15637ed4 RG |
747 | |
748 | /*******************************************************\ | |
749 | * If the device is not valid.. abandon ship * | |
750 | \*******************************************************/ | |
4f6ede5d | 751 | if (!(cd_driver->cd_data[unit]->flags & CDVALID)) |
15637ed4 RG |
752 | return(EIO); |
753 | switch(cmd) | |
754 | { | |
755 | ||
756 | case DIOCSBAD: | |
757 | error = EINVAL; | |
758 | break; | |
759 | ||
760 | case DIOCGDINFO: | |
761 | *(struct disklabel *)addr = cd->disklabel; | |
762 | break; | |
763 | ||
764 | case DIOCGPART: | |
765 | ((struct partinfo *)addr)->disklab = &cd->disklabel; | |
766 | ((struct partinfo *)addr)->part = | |
767 | &cd->disklabel.d_partitions[PARTITION(dev)]; | |
768 | break; | |
769 | ||
770 | case DIOCWDINFO: | |
771 | case DIOCSDINFO: | |
772 | if ((flag & FWRITE) == 0) | |
773 | error = EBADF; | |
774 | else | |
775 | error = setdisklabel(&cd->disklabel, | |
776 | (struct disklabel *)addr, | |
777 | /*(cd->flags & DKFL_BSDLABEL) ? cd->openparts : */0, | |
778 | 0); | |
779 | if (error == 0) { | |
780 | cd->flags |= CDHAVELABEL; | |
781 | } | |
782 | break; | |
783 | ||
784 | case DIOCWLABEL: | |
785 | error = EBADF; | |
786 | break; | |
787 | ||
788 | case CDIOCPLAYTRACKS: | |
789 | { | |
790 | struct ioc_play_track *args | |
791 | = (struct ioc_play_track *)addr; | |
792 | struct cd_mode_data data; | |
793 | if(error = cd_get_mode(unit,&data,AUDIO_PAGE)) | |
794 | break; | |
869c4419 RG |
795 | data.page.audio.flags &= ~CD_PA_SOTC; |
796 | data.page.audio.flags |= CD_PA_IMMED; | |
15637ed4 RG |
797 | if(error = cd_set_mode(unit,&data)) |
798 | break; | |
799 | return(cd_play_tracks(unit | |
800 | ,args->start_track | |
801 | ,args->start_index | |
802 | ,args->end_track | |
803 | ,args->end_index | |
804 | )); | |
805 | } | |
806 | break; | |
d4284689 RG |
807 | case CDIOCPLAYMSF: |
808 | { | |
809 | struct ioc_play_msf *args | |
810 | = (struct ioc_play_msf *)addr; | |
811 | struct cd_mode_data data; | |
812 | if(error = cd_get_mode(unit,&data,AUDIO_PAGE)) | |
813 | break; | |
814 | data.page.audio.flags &= ~CD_PA_SOTC; | |
815 | data.page.audio.flags |= CD_PA_IMMED; | |
816 | if(error = cd_set_mode(unit,&data)) | |
817 | break; | |
818 | return(cd_play_msf(unit | |
819 | ,args->start_m | |
820 | ,args->start_s | |
821 | ,args->start_f | |
822 | ,args->end_m | |
823 | ,args->end_s | |
824 | ,args->end_f | |
825 | )); | |
826 | } | |
827 | break; | |
15637ed4 RG |
828 | case CDIOCPLAYBLOCKS: |
829 | { | |
830 | struct ioc_play_blocks *args | |
831 | = (struct ioc_play_blocks *)addr; | |
832 | struct cd_mode_data data; | |
833 | if(error = cd_get_mode(unit,&data,AUDIO_PAGE)) | |
834 | break; | |
869c4419 RG |
835 | data.page.audio.flags &= ~CD_PA_SOTC; |
836 | data.page.audio.flags |= CD_PA_IMMED; | |
15637ed4 RG |
837 | if(error = cd_set_mode(unit,&data)) |
838 | break; | |
839 | return(cd_play(unit,args->blk,args->len)); | |
840 | ||
841 | ||
842 | } | |
843 | break; | |
844 | case CDIOCREADSUBCHANNEL: | |
845 | { | |
846 | struct ioc_read_subchannel *args | |
847 | = (struct ioc_read_subchannel *)addr; | |
848 | struct cd_sub_channel_info data; | |
849 | int len=args->data_len; | |
850 | if(len>sizeof(data)|| | |
851 | len<sizeof(struct cd_sub_channel_header)) { | |
852 | error=EINVAL; | |
853 | break; | |
854 | } | |
855 | if(error = cd_read_subchannel(unit,args->address_format, | |
856 | args->data_format,args->track,&data,len)) { | |
857 | break; | |
858 | } | |
859 | len=MIN(len,((data.header.data_len[0]<<8)+data.header.data_len[1]+ | |
860 | sizeof(struct cd_sub_channel_header))); | |
861 | if(copyout(&data,args->data,len)!=0) { | |
862 | error=EFAULT; | |
863 | } | |
864 | } | |
865 | break; | |
866 | case CDIOREADTOCHEADER: | |
867 | { | |
868 | struct ioc_toc_header th; | |
869 | if( error = cd_read_toc(unit,0,0,&th,sizeof(th))) | |
870 | break; | |
871 | th.len=(th.len&0xff)<<8+((th.len>>8)&0xff); | |
872 | bcopy(&th,addr,sizeof(th)); | |
873 | } | |
874 | break; | |
875 | case CDIOREADTOCENTRYS: | |
876 | { | |
877 | struct ioc_read_toc_entry *te= | |
878 | (struct ioc_read_toc_entry *)addr; | |
879 | struct cd_toc_entry data[65]; | |
880 | struct ioc_toc_header *th; | |
881 | int len=te->data_len; | |
882 | th=(struct ioc_toc_header *)data; | |
883 | ||
884 | if(len>sizeof(data) || len<sizeof(struct cd_toc_entry)) { | |
885 | error=EINVAL; | |
886 | break; | |
887 | } | |
888 | if(error = cd_read_toc(unit,te->address_format, | |
889 | te->starting_track, | |
890 | data, | |
891 | len)) | |
892 | break; | |
893 | len=MIN(len,((((th->len&0xff)<<8)+((th->len>>8)))+ | |
894 | sizeof(*th))); | |
895 | if(copyout(th,te->data,len)!=0) { | |
896 | error=EFAULT; | |
897 | } | |
898 | ||
899 | } | |
900 | break; | |
901 | case CDIOCSETPATCH: | |
902 | { | |
903 | struct ioc_patch *arg = (struct ioc_patch *)addr; | |
904 | struct cd_mode_data data; | |
905 | if(error = cd_get_mode(unit,&data,AUDIO_PAGE)) | |
906 | break; | |
907 | data.page.audio.port[LEFT_PORT].channels = arg->patch[0]; | |
908 | data.page.audio.port[RIGHT_PORT].channels = arg->patch[1]; | |
909 | data.page.audio.port[2].channels = arg->patch[2]; | |
910 | data.page.audio.port[3].channels = arg->patch[3]; | |
911 | if(error = cd_set_mode(unit,&data)) | |
912 | break; | |
913 | } | |
914 | break; | |
915 | case CDIOCGETVOL: | |
916 | { | |
917 | struct ioc_vol *arg = (struct ioc_vol *)addr; | |
918 | struct cd_mode_data data; | |
919 | if(error = cd_get_mode(unit,&data,AUDIO_PAGE)) | |
920 | break; | |
921 | arg->vol[LEFT_PORT] = data.page.audio.port[LEFT_PORT].volume; | |
922 | arg->vol[RIGHT_PORT] = data.page.audio.port[RIGHT_PORT].volume; | |
923 | arg->vol[2] = data.page.audio.port[2].volume; | |
924 | arg->vol[3] = data.page.audio.port[3].volume; | |
925 | } | |
926 | break; | |
927 | case CDIOCSETVOL: | |
928 | { | |
929 | struct ioc_vol *arg = (struct ioc_vol *)addr; | |
930 | struct cd_mode_data data; | |
931 | if(error = cd_get_mode(unit,&data,AUDIO_PAGE)) | |
932 | break; | |
933 | data.page.audio.port[LEFT_PORT].volume = arg->vol[LEFT_PORT]; | |
934 | data.page.audio.port[RIGHT_PORT].volume = arg->vol[RIGHT_PORT]; | |
935 | data.page.audio.port[2].volume = arg->vol[2]; | |
936 | data.page.audio.port[3].volume = arg->vol[3]; | |
937 | if(error = cd_set_mode(unit,&data)) | |
938 | break; | |
939 | } | |
940 | break; | |
941 | case CDIOCSETMONO: | |
942 | { | |
943 | struct ioc_vol *arg = (struct ioc_vol *)addr; | |
944 | struct cd_mode_data data; | |
945 | if(error = cd_get_mode(unit,&data,AUDIO_PAGE)) | |
946 | break; | |
947 | data.page.audio.port[LEFT_PORT].channels = LEFT_CHANNEL|RIGHT_CHANNEL|4|8; | |
948 | data.page.audio.port[RIGHT_PORT].channels = LEFT_CHANNEL|RIGHT_CHANNEL; | |
949 | data.page.audio.port[2].channels = 0; | |
950 | data.page.audio.port[3].channels = 0; | |
951 | if(error = cd_set_mode(unit,&data)) | |
952 | break; | |
953 | } | |
954 | break; | |
955 | case CDIOCSETSTERIO: | |
956 | { | |
957 | struct ioc_vol *arg = (struct ioc_vol *)addr; | |
958 | struct cd_mode_data data; | |
959 | if(error = cd_get_mode(unit,&data,AUDIO_PAGE)) | |
960 | break; | |
961 | data.page.audio.port[LEFT_PORT].channels = LEFT_CHANNEL; | |
962 | data.page.audio.port[RIGHT_PORT].channels = RIGHT_CHANNEL; | |
963 | data.page.audio.port[2].channels = 0; | |
964 | data.page.audio.port[3].channels = 0; | |
965 | if(error = cd_set_mode(unit,&data)) | |
966 | break; | |
967 | } | |
968 | break; | |
969 | case CDIOCSETMUTE: | |
970 | { | |
971 | struct ioc_vol *arg = (struct ioc_vol *)addr; | |
972 | struct cd_mode_data data; | |
973 | if(error = cd_get_mode(unit,&data,AUDIO_PAGE)) | |
974 | break; | |
975 | data.page.audio.port[LEFT_PORT].channels = 0; | |
976 | data.page.audio.port[RIGHT_PORT].channels = 0; | |
977 | data.page.audio.port[2].channels = 0; | |
978 | data.page.audio.port[3].channels = 0; | |
979 | if(error = cd_set_mode(unit,&data)) | |
980 | break; | |
981 | } | |
982 | break; | |
983 | case CDIOCSETLEFT: | |
984 | { | |
985 | struct ioc_vol *arg = (struct ioc_vol *)addr; | |
986 | struct cd_mode_data data; | |
987 | if(error = cd_get_mode(unit,&data,AUDIO_PAGE)) | |
988 | break; | |
869c4419 RG |
989 | data.page.audio.port[LEFT_PORT].channels = LEFT_CHANNEL; |
990 | data.page.audio.port[RIGHT_PORT].channels = LEFT_CHANNEL; | |
991 | data.page.audio.port[2].channels = 0; | |
992 | data.page.audio.port[3].channels = 0; | |
15637ed4 RG |
993 | if(error = cd_set_mode(unit,&data)) |
994 | break; | |
995 | } | |
996 | break; | |
997 | case CDIOCSETRIGHT: | |
998 | { | |
999 | struct ioc_vol *arg = (struct ioc_vol *)addr; | |
1000 | struct cd_mode_data data; | |
1001 | if(error = cd_get_mode(unit,&data,AUDIO_PAGE)) | |
1002 | break; | |
1003 | data.page.audio.port[LEFT_PORT].channels = RIGHT_CHANNEL; | |
1004 | data.page.audio.port[RIGHT_PORT].channels = RIGHT_CHANNEL; | |
1005 | data.page.audio.port[2].channels = 0; | |
1006 | data.page.audio.port[3].channels = 0; | |
1007 | if(error = cd_set_mode(unit,&data)) | |
1008 | break; | |
1009 | } | |
1010 | break; | |
1011 | case CDIOCRESUME: | |
1012 | error = cd_pause(unit,1); | |
1013 | break; | |
1014 | case CDIOCPAUSE: | |
1015 | error = cd_pause(unit,0); | |
1016 | break; | |
1017 | case CDIOCSTART: | |
1018 | error = cd_start_unit(unit,part,CD_START); | |
1019 | break; | |
1020 | case CDIOCSTOP: | |
1021 | error = cd_start_unit(unit,part,CD_STOP); | |
1022 | break; | |
1023 | case CDIOCEJECT: | |
1024 | error = cd_start_unit(unit,part,CD_EJECT); | |
1025 | break; | |
1026 | case CDIOCSETDEBUG: | |
1027 | scsi_debug = 0xfff; cd_debug = 0xfff; | |
1028 | break; | |
1029 | case CDIOCCLRDEBUG: | |
1030 | scsi_debug = 0; cd_debug = 0; | |
1031 | break; | |
1032 | case CDIOCRESET: | |
1033 | return(cd_reset(unit)); | |
1034 | break; | |
1035 | default: | |
1036 | error = ENOTTY; | |
1037 | break; | |
1038 | } | |
1039 | return (error); | |
1040 | } | |
1041 | ||
1042 | ||
1043 | /*******************************************************\ | |
1044 | * Load the label information on the named device * | |
1045 | * * | |
1046 | * EVENTUALLY take information about different * | |
1047 | * data tracks from the TOC and put it in the disklabel * | |
1048 | \*******************************************************/ | |
1049 | int cdgetdisklabel(unit) | |
1050 | unsigned char unit; | |
1051 | { | |
1052 | /*unsigned int n, m;*/ | |
1053 | char *errstring; | |
1054 | struct dos_partition *dos_partition_p; | |
4f6ede5d | 1055 | struct cd_data *cd; |
15637ed4 | 1056 | |
4f6ede5d | 1057 | cd = cd_driver->cd_data[unit]; |
15637ed4 | 1058 | /*******************************************************\ |
de4fe9fb | 1059 | * If the info is already loaded, use it * |
15637ed4 RG |
1060 | \*******************************************************/ |
1061 | if(cd->flags & CDHAVELABEL) return; | |
1062 | ||
1063 | bzero(&cd->disklabel,sizeof(struct disklabel)); | |
1064 | /*******************************************************\ | |
1065 | * make partition 3 the whole disk in case of failure * | |
1066 | * then get pdinfo * | |
1067 | \*******************************************************/ | |
1068 | strncpy(cd->disklabel.d_typename,"scsi cd_rom",16); | |
1069 | strncpy(cd->disklabel.d_packname,"ficticious",16); | |
1070 | cd->disklabel.d_secsize = cd->params.blksize; /* as long as it's not 0 */ | |
1071 | cd->disklabel.d_nsectors = 100; | |
1072 | cd->disklabel.d_ntracks = 1; | |
1073 | cd->disklabel.d_ncylinders = (cd->params.disksize / 100) + 1; | |
1074 | cd->disklabel.d_secpercyl = 100; | |
1075 | cd->disklabel.d_secperunit = cd->params.disksize; | |
1076 | cd->disklabel.d_rpm = 300; | |
1077 | cd->disklabel.d_interleave = 1; | |
1078 | cd->disklabel.d_flags = D_REMOVABLE; | |
1079 | ||
1080 | cd->disklabel.d_npartitions = 1; | |
1081 | cd->disklabel.d_partitions[0].p_offset = 0; | |
1082 | cd->disklabel.d_partitions[0].p_size = cd->params.disksize; | |
1083 | cd->disklabel.d_partitions[0].p_fstype = 9; | |
1084 | ||
1085 | cd->disklabel.d_magic = DISKMAGIC; | |
1086 | cd->disklabel.d_magic2 = DISKMAGIC; | |
1087 | cd->disklabel.d_checksum = dkcksum(&(cd->disklabel)); | |
1088 | ||
1089 | /*******************************************************\ | |
1090 | * Signal to other users and routines that we now have a * | |
1091 | * disklabel that represents the media (maybe) * | |
1092 | \*******************************************************/ | |
1093 | cd->flags |= CDHAVELABEL; | |
1094 | return(ESUCCESS); | |
1095 | } | |
1096 | ||
1097 | /*******************************************************\ | |
1098 | * Find out form the device what it's capacity is * | |
1099 | \*******************************************************/ | |
1100 | cd_size(unit, flags) | |
1101 | { | |
1102 | struct scsi_read_cd_cap_data rdcap; | |
1103 | struct scsi_read_cd_capacity scsi_cmd; | |
1104 | int size; | |
1105 | int blksize; | |
1106 | ||
1107 | /*******************************************************\ | |
1108 | * make up a scsi command and ask the scsi driver to do * | |
1109 | * it for you. * | |
1110 | \*******************************************************/ | |
1111 | bzero(&scsi_cmd, sizeof(scsi_cmd)); | |
1112 | scsi_cmd.op_code = READ_CD_CAPACITY; | |
1113 | ||
1114 | /*******************************************************\ | |
1115 | * If the command works, interpret the result as a 4 byte* | |
1116 | * number of blocks * | |
1117 | \*******************************************************/ | |
1118 | if (cd_scsi_cmd(unit, | |
1119 | &scsi_cmd, | |
1120 | sizeof(scsi_cmd), | |
1121 | &rdcap, | |
1122 | sizeof(rdcap), | |
1123 | 2000, | |
1124 | flags) != 0) | |
1125 | { | |
98639498 | 1126 | printf("cd%d: could not get size\n", unit); |
15637ed4 RG |
1127 | return(0); |
1128 | } else { | |
1129 | size = rdcap.addr_0 + 1 ; | |
1130 | size += rdcap.addr_1 << 8; | |
1131 | size += rdcap.addr_2 << 16; | |
1132 | size += rdcap.addr_3 << 24; | |
1133 | blksize = rdcap.length_0 ; | |
1134 | blksize += rdcap.length_1 << 8; | |
1135 | blksize += rdcap.length_2 << 16; | |
1136 | blksize += rdcap.length_3 << 24; | |
1137 | } | |
de4fe9fb | 1138 | #ifdef CDDEBUG |
15637ed4 | 1139 | if(cd_debug)printf("cd%d: %d %d byte blocks\n",unit,size,blksize); |
de4fe9fb | 1140 | #endif /*CDDEBUG*/ |
4f6ede5d RG |
1141 | cd_driver->cd_data[unit]->params.disksize = size; |
1142 | cd_driver->cd_data[unit]->params.blksize = blksize; | |
15637ed4 RG |
1143 | return(size); |
1144 | } | |
1145 | ||
1146 | /*******************************************************\ | |
1147 | * Check with the device that it is ok, (via scsi driver)* | |
1148 | \*******************************************************/ | |
1149 | cd_req_sense(unit, flags) | |
1150 | { | |
1151 | struct scsi_sense_data sense_data; | |
1152 | struct scsi_sense scsi_cmd; | |
1153 | ||
1154 | bzero(&scsi_cmd, sizeof(scsi_cmd)); | |
1155 | scsi_cmd.op_code = REQUEST_SENSE; | |
1156 | scsi_cmd.length = sizeof(sense_data); | |
1157 | ||
1158 | if (cd_scsi_cmd(unit, | |
1159 | &scsi_cmd, | |
1160 | sizeof(scsi_cmd), | |
1161 | &sense_data, | |
1162 | sizeof(sense_data), | |
1163 | 2000, | |
1164 | flags) != 0) | |
1165 | { | |
1166 | return(ENXIO); | |
1167 | } | |
1168 | else | |
1169 | return(0); | |
1170 | } | |
1171 | ||
1172 | /*******************************************************\ | |
1173 | * Get the requested page into the buffer given * | |
1174 | \*******************************************************/ | |
1175 | cd_get_mode(unit,data,page) | |
1176 | int unit; | |
1177 | struct cd_mode_data *data; | |
1178 | int page; | |
1179 | { | |
1180 | struct scsi_mode_sense scsi_cmd; | |
1181 | int retval; | |
1182 | ||
1183 | bzero(&scsi_cmd, sizeof(scsi_cmd)); | |
1184 | bzero(data,sizeof(*data)); | |
1185 | scsi_cmd.op_code = MODE_SENSE; | |
869c4419 | 1186 | scsi_cmd.page = page; |
15637ed4 RG |
1187 | scsi_cmd.length = sizeof(*data) & 0xff; |
1188 | retval = cd_scsi_cmd(unit, | |
1189 | &scsi_cmd, | |
1190 | sizeof(scsi_cmd), | |
1191 | data, | |
1192 | sizeof(*data), | |
1193 | 20000, /* should be immed */ | |
1194 | 0); | |
1195 | return (retval); | |
1196 | } | |
1197 | /*******************************************************\ | |
1198 | * Get the requested page into the buffer given * | |
1199 | \*******************************************************/ | |
1200 | cd_set_mode(unit,data) | |
1201 | int unit; | |
1202 | struct cd_mode_data *data; | |
1203 | { | |
1204 | struct scsi_mode_select scsi_cmd; | |
1205 | ||
1206 | bzero(&scsi_cmd, sizeof(scsi_cmd)); | |
1207 | scsi_cmd.op_code = MODE_SELECT; | |
869c4419 | 1208 | scsi_cmd.byte2 |= SMS_PF; |
15637ed4 RG |
1209 | scsi_cmd.length = sizeof(*data) & 0xff; |
1210 | data->header.data_length = 0; | |
1211 | /*show_mem(data,sizeof(*data));/**/ | |
1212 | return (cd_scsi_cmd(unit, | |
1213 | &scsi_cmd, | |
1214 | sizeof(scsi_cmd), | |
1215 | data, | |
1216 | sizeof(*data), | |
1217 | 20000, /* should be immed */ | |
1218 | 0) | |
1219 | ); | |
1220 | } | |
1221 | /*******************************************************\ | |
1222 | * Get scsi driver to send a "start playing" command * | |
1223 | \*******************************************************/ | |
1224 | cd_play(unit,blk,len) | |
1225 | int unit,blk,len; | |
1226 | { | |
1227 | struct scsi_play scsi_cmd; | |
1228 | int retval; | |
1229 | ||
1230 | bzero(&scsi_cmd, sizeof(scsi_cmd)); | |
1231 | scsi_cmd.op_code = PLAY; | |
1232 | scsi_cmd.blk_addr[0] = (blk >> 24) & 0xff; | |
1233 | scsi_cmd.blk_addr[1] = (blk >> 16) & 0xff; | |
1234 | scsi_cmd.blk_addr[2] = (blk >> 8) & 0xff; | |
1235 | scsi_cmd.blk_addr[3] = blk & 0xff; | |
1236 | scsi_cmd.xfer_len[0] = (len >> 8) & 0xff; | |
1237 | scsi_cmd.xfer_len[1] = len & 0xff; | |
1238 | retval = cd_scsi_cmd(unit, | |
1239 | &scsi_cmd, | |
1240 | sizeof(scsi_cmd), | |
1241 | 0, | |
1242 | 0, | |
1243 | 200000, /* should be immed */ | |
1244 | 0); | |
1245 | return(retval); | |
1246 | } | |
1247 | /*******************************************************\ | |
1248 | * Get scsi driver to send a "start playing" command * | |
1249 | \*******************************************************/ | |
1250 | cd_play_big(unit,blk,len) | |
1251 | int unit,blk,len; | |
1252 | { | |
1253 | struct scsi_play_big scsi_cmd; | |
1254 | int retval; | |
1255 | ||
1256 | bzero(&scsi_cmd, sizeof(scsi_cmd)); | |
1257 | scsi_cmd.op_code = PLAY_BIG; | |
1258 | scsi_cmd.blk_addr[0] = (blk >> 24) & 0xff; | |
1259 | scsi_cmd.blk_addr[1] = (blk >> 16) & 0xff; | |
1260 | scsi_cmd.blk_addr[2] = (blk >> 8) & 0xff; | |
1261 | scsi_cmd.blk_addr[3] = blk & 0xff; | |
1262 | scsi_cmd.xfer_len[0] = (len >> 24) & 0xff; | |
1263 | scsi_cmd.xfer_len[1] = (len >> 16) & 0xff; | |
1264 | scsi_cmd.xfer_len[2] = (len >> 8) & 0xff; | |
1265 | scsi_cmd.xfer_len[3] = len & 0xff; | |
1266 | retval = cd_scsi_cmd(unit, | |
1267 | &scsi_cmd, | |
1268 | sizeof(scsi_cmd), | |
1269 | 0, | |
1270 | 0, | |
1271 | 20000, /* should be immed */ | |
1272 | 0); | |
1273 | return(retval); | |
1274 | } | |
1275 | /*******************************************************\ | |
1276 | * Get scsi driver to send a "start playing" command * | |
1277 | \*******************************************************/ | |
1278 | cd_play_tracks(unit,strack,sindex,etrack,eindex) | |
1279 | int unit,strack,sindex,etrack,eindex; | |
1280 | { | |
1281 | struct scsi_play_track scsi_cmd; | |
1282 | int retval; | |
1283 | ||
1284 | bzero(&scsi_cmd, sizeof(scsi_cmd)); | |
1285 | scsi_cmd.op_code = PLAY_TRACK; | |
1286 | scsi_cmd.start_track = strack; | |
1287 | scsi_cmd.start_index = sindex; | |
1288 | scsi_cmd.end_track = etrack; | |
1289 | scsi_cmd.end_index = eindex; | |
1290 | retval = cd_scsi_cmd(unit, | |
1291 | &scsi_cmd, | |
1292 | sizeof(scsi_cmd), | |
1293 | 0, | |
1294 | 0, | |
1295 | 20000, /* should be immed */ | |
1296 | 0); | |
1297 | return(retval); | |
1298 | } | |
1299 | /*******************************************************\ | |
d4284689 RG |
1300 | * Get scsi driver to send a "play msf" command * |
1301 | \*******************************************************/ | |
1302 | cd_play_msf(unit,startm,starts,startf,endm,ends,endf) | |
1303 | int unit,startm,starts,startf,endm,ends,endf; | |
1304 | { | |
1305 | struct scsi_play_msf scsi_cmd; | |
1306 | ||
1307 | bzero(&scsi_cmd, sizeof(scsi_cmd)); | |
1308 | scsi_cmd.op_code = PLAY_MSF; | |
1309 | scsi_cmd.start_m=startm; | |
1310 | scsi_cmd.start_s=starts; | |
1311 | scsi_cmd.start_f=startf; | |
1312 | scsi_cmd.end_m=endm; | |
1313 | scsi_cmd.end_s=ends; | |
1314 | scsi_cmd.end_f=endf; | |
1315 | ||
1316 | return (cd_scsi_cmd(unit, | |
1317 | &scsi_cmd, | |
1318 | sizeof(scsi_cmd), | |
1319 | 0, | |
1320 | 0, | |
1321 | 2000, | |
1322 | 0)); | |
1323 | } | |
1324 | /*******************************************************\ | |
15637ed4 RG |
1325 | * Get scsi driver to send a "start up" command * |
1326 | \*******************************************************/ | |
1327 | cd_pause(unit,go) | |
1328 | int unit,go; | |
1329 | { | |
1330 | struct scsi_pause scsi_cmd; | |
1331 | ||
1332 | bzero(&scsi_cmd, sizeof(scsi_cmd)); | |
1333 | scsi_cmd.op_code = PAUSE; | |
1334 | scsi_cmd.resume = go; | |
1335 | ||
1336 | return (cd_scsi_cmd(unit, | |
1337 | &scsi_cmd, | |
1338 | sizeof(scsi_cmd), | |
1339 | 0, | |
1340 | 0, | |
1341 | 2000, | |
1342 | 0)); | |
1343 | } | |
1344 | /*******************************************************\ | |
1345 | * Get scsi driver to send a "start up" command * | |
1346 | \*******************************************************/ | |
1347 | cd_reset(unit) | |
1348 | int unit; | |
1349 | { | |
1350 | return(cd_scsi_cmd(unit,0,0,0,0,2000,SCSI_RESET)); | |
1351 | } | |
1352 | /*******************************************************\ | |
1353 | * Get scsi driver to send a "start up" command * | |
1354 | \*******************************************************/ | |
1355 | cd_start_unit(unit,part,type) | |
1356 | { | |
1357 | struct scsi_start_stop scsi_cmd; | |
1358 | ||
4f6ede5d | 1359 | if(type==CD_EJECT && (cd_driver->cd_data[unit]->openparts&~(1<<part)) == 0 ) { |
15637ed4 RG |
1360 | cd_prevent_unit(unit,CD_EJECT,0); |
1361 | } | |
1362 | ||
1363 | bzero(&scsi_cmd, sizeof(scsi_cmd)); | |
1364 | scsi_cmd.op_code = START_STOP; | |
869c4419 RG |
1365 | scsi_cmd.how |= (type==CD_START)?SSS_START:0; |
1366 | scsi_cmd.how |= (type==CD_EJECT)?SSS_LOEJ:0; | |
15637ed4 RG |
1367 | |
1368 | if (cd_scsi_cmd(unit, | |
1369 | &scsi_cmd, | |
1370 | sizeof(scsi_cmd), | |
1371 | 0, | |
1372 | 0, | |
1373 | 2000, | |
1374 | 0) != 0) { | |
1375 | return(ENXIO); | |
1376 | } else | |
1377 | return(0); | |
1378 | } | |
1379 | /*******************************************************\ | |
1380 | * Prevent or allow the user to remove the disk * | |
1381 | \*******************************************************/ | |
1382 | cd_prevent_unit(unit,type,flags) | |
1383 | int unit,type,flags; | |
1384 | { | |
1385 | struct scsi_prevent scsi_cmd; | |
1386 | ||
4f6ede5d | 1387 | if(type==CD_EJECT || type==PR_PREVENT || cd_driver->cd_data[unit]->openparts == 0 ) { |
15637ed4 RG |
1388 | bzero(&scsi_cmd, sizeof(scsi_cmd)); |
1389 | scsi_cmd.op_code = PREVENT_ALLOW; | |
869c4419 | 1390 | scsi_cmd.how = (type==CD_EJECT)?PR_ALLOW:type; |
15637ed4 RG |
1391 | if (cd_scsi_cmd(unit, |
1392 | &scsi_cmd, | |
1393 | sizeof(struct scsi_prevent), | |
1394 | 0, | |
1395 | 0, | |
1396 | 5000, | |
1397 | 0) != 0) | |
1398 | { | |
1399 | if(!(flags & SCSI_SILENT)) | |
98639498 | 1400 | printf("cd%d: cannot prevent/allow\n", unit); |
15637ed4 RG |
1401 | return(0); |
1402 | } | |
1403 | } | |
1404 | return(1); | |
1405 | } | |
1406 | ||
1407 | /******************************************************\ | |
1408 | * Read Subchannel * | |
1409 | \******************************************************/ | |
1410 | ||
1411 | cd_read_subchannel(unit,mode,format,track,data,len) | |
1412 | int unit,mode,format,len; | |
1413 | struct cd_sub_channel_info *data; | |
1414 | { | |
1415 | struct scsi_read_subchannel scsi_cmd; | |
1416 | int error; | |
1417 | ||
1418 | bzero(&scsi_cmd,sizeof(scsi_cmd)); | |
1419 | ||
1420 | scsi_cmd.op_code=READ_SUBCHANNEL; | |
1421 | if(mode==CD_MSF_FORMAT) | |
869c4419 RG |
1422 | scsi_cmd.byte2 |= CD_MSF; |
1423 | scsi_cmd.byte3=SRS_SUBQ; | |
15637ed4 RG |
1424 | scsi_cmd.subchan_format=format; |
1425 | scsi_cmd.track=track; | |
1426 | scsi_cmd.data_len[0]=(len)>>8; | |
1427 | scsi_cmd.data_len[1]=(len)&0xff; | |
1428 | return cd_scsi_cmd(unit, | |
1429 | &scsi_cmd, | |
1430 | sizeof(struct scsi_read_subchannel), | |
1431 | data, | |
1432 | len, | |
1433 | 5000, | |
1434 | 0); | |
1435 | } | |
1436 | ||
1437 | /*******************************************************\ | |
1438 | * Read Table of contents * | |
1439 | \*******************************************************/ | |
1440 | cd_read_toc(unit,mode,start,data,len) | |
1441 | int unit,mode,start,len; | |
1442 | struct cd_toc_entry *data; | |
1443 | { | |
1444 | struct scsi_read_toc scsi_cmd; | |
1445 | int error; | |
1446 | int ntoc; | |
1447 | ||
1448 | bzero(&scsi_cmd,sizeof(scsi_cmd)); | |
1449 | /*if(len!=sizeof(struct ioc_toc_header)) | |
1450 | ntoc=((len)-sizeof(struct ioc_toc_header))/sizeof(struct cd_toc_entry); | |
1451 | else*/ | |
1452 | ntoc=len; | |
1453 | ||
1454 | scsi_cmd.op_code=READ_TOC; | |
1455 | if(mode==CD_MSF_FORMAT) | |
869c4419 | 1456 | scsi_cmd.byte2 |= CD_MSF; |
15637ed4 RG |
1457 | scsi_cmd.from_track=start; |
1458 | scsi_cmd.data_len[0]=(ntoc)>>8; | |
1459 | scsi_cmd.data_len[1]=(ntoc)&0xff; | |
1460 | return cd_scsi_cmd(unit, | |
1461 | &scsi_cmd, | |
1462 | sizeof(struct scsi_read_toc), | |
1463 | data, | |
1464 | len, | |
1465 | 5000, | |
1466 | 0); | |
1467 | } | |
1468 | ||
1469 | ||
1470 | #define b2tol(a) (((unsigned)(a##_1) << 8) + (unsigned)a##_0 ) | |
1471 | ||
1472 | /*******************************************************\ | |
1473 | * Get the scsi driver to send a full inquiry to the * | |
1474 | * device and use the results to fill out the disk * | |
1475 | * parameter structure. * | |
1476 | \*******************************************************/ | |
1477 | ||
1478 | int cd_get_parms(unit, flags) | |
1479 | { | |
4f6ede5d | 1480 | struct cd_data *cd = cd_driver->cd_data[unit]; |
15637ed4 RG |
1481 | |
1482 | /*******************************************************\ | |
1483 | * First check if we have it all loaded * | |
1484 | \*******************************************************/ | |
1485 | if(cd->flags & CDVALID) return(0); | |
1486 | /*******************************************************\ | |
1487 | * give a number of sectors so that sec * trks * cyls * | |
1488 | * is <= disk_size * | |
1489 | \*******************************************************/ | |
1490 | if(cd_size(unit, flags)) | |
1491 | { | |
1492 | cd->flags |= CDVALID; | |
1493 | return(0); | |
1494 | } | |
1495 | else | |
1496 | { | |
1497 | return(ENXIO); | |
1498 | } | |
1499 | } | |
1500 | ||
1501 | /*******************************************************\ | |
1502 | * close the device.. only called if we are the LAST * | |
1503 | * occurence of an open device * | |
1504 | \*******************************************************/ | |
1505 | cdclose(dev) | |
1506 | dev_t dev; | |
1507 | { | |
1508 | unsigned char unit, part; | |
1509 | unsigned int old_priority; | |
1510 | ||
1511 | unit = UNIT(dev); | |
1512 | part = PARTITION(dev); | |
de4fe9fb | 1513 | #ifdef CDDEBUG |
15637ed4 | 1514 | if(scsi_debug & TRACEOPENS) |
de4fe9fb RG |
1515 | printf("cd%d: closing part %d\n",unit,part); |
1516 | #endif | |
4f6ede5d RG |
1517 | cd_driver->cd_data[unit]->partflags[part] &= ~CDOPEN; |
1518 | cd_driver->cd_data[unit]->openparts &= ~(1 << part); | |
15637ed4 RG |
1519 | cd_prevent_unit(unit,PR_ALLOW,SCSI_SILENT); |
1520 | return(0); | |
1521 | } | |
1522 | ||
1523 | /*******************************************************\ | |
1524 | * ask the scsi driver to perform a command for us. * | |
1525 | * Call it through the switch table, and tell it which * | |
1526 | * sub-unit we want, and what target and lu we wish to * | |
1527 | * talk to. Also tell it where to find the command * | |
1528 | * how long int is. * | |
1529 | * Also tell it where to read/write the data, and how * | |
1530 | * long the data is supposed to be * | |
1531 | \*******************************************************/ | |
1532 | int cd_scsi_cmd(unit,scsi_cmd,cmdlen,data_addr,datalen,timeout,flags) | |
1533 | ||
1534 | int unit,flags; | |
1535 | struct scsi_generic *scsi_cmd; | |
1536 | int cmdlen; | |
1537 | int timeout; | |
1538 | u_char *data_addr; | |
1539 | int datalen; | |
1540 | { | |
1541 | struct scsi_xfer *xs; | |
1542 | int retval; | |
1543 | int s; | |
4f6ede5d | 1544 | struct cd_data *cd = cd_driver->cd_data[unit]; |
15637ed4 | 1545 | |
de4fe9fb | 1546 | #ifdef CDDEBUG |
15637ed4 | 1547 | if(scsi_debug & PRINTROUTINES) printf("\ncd_scsi_cmd%d ",unit); |
de4fe9fb | 1548 | #endif /*CDDEBUG*/ |
15637ed4 RG |
1549 | if(cd->sc_sw) /* If we have a scsi driver */ |
1550 | { | |
1551 | xs = cd_get_xs(unit,flags); /* should wait unless booting */ | |
1552 | if(!xs) | |
1553 | { | |
98639498 | 1554 | printf("cd%d: scsi_cmd controller busy" |
15637ed4 RG |
1555 | " (this should never happen)\n",unit); |
1556 | return(EBUSY); | |
1557 | } | |
1558 | xs->flags |= INUSE; | |
1559 | /*******************************************************\ | |
1560 | * Fill out the scsi_xfer structure * | |
1561 | \*******************************************************/ | |
1562 | xs->flags |= flags; | |
1563 | xs->adapter = cd->ctlr; | |
1564 | xs->targ = cd->targ; | |
1565 | xs->lu = cd->lu; | |
1566 | xs->retries = CD_RETRIES; | |
1567 | xs->timeout = timeout; | |
1568 | xs->cmd = scsi_cmd; | |
1569 | xs->cmdlen = cmdlen; | |
1570 | xs->data = data_addr; | |
1571 | xs->datalen = datalen; | |
1572 | xs->resid = datalen; | |
1573 | xs->when_done = (flags & SCSI_NOMASK) | |
1574 | ?(int (*)())0 | |
1575 | :cd_done; | |
1576 | xs->done_arg = unit; | |
1577 | xs->done_arg2 = (int)xs; | |
1578 | retry: xs->error = XS_NOERROR; | |
1579 | xs->bp = 0; | |
1580 | retval = (*(cd->sc_sw->scsi_cmd))(xs); | |
1581 | switch(retval) | |
1582 | { | |
1583 | case SUCCESSFULLY_QUEUED: | |
1584 | s = splbio(); | |
1585 | while(!(xs->flags & ITSDONE)) | |
1586 | sleep(xs,PRIBIO+1); | |
1587 | splx(s); | |
1588 | ||
1589 | case HAD_ERROR: | |
1590 | /*printf("err = %d ",xs->error);*/ | |
1591 | switch(xs->error) | |
1592 | { | |
1593 | case XS_NOERROR: | |
1594 | retval = ESUCCESS; | |
1595 | break; | |
1596 | case XS_SENSE: | |
1597 | retval = (cd_interpret_sense(unit,xs)); | |
1598 | break; | |
1599 | case XS_DRIVER_STUFFUP: | |
1600 | retval = EIO; | |
1601 | break; | |
1602 | ||
1603 | ||
1604 | case XS_BUSY: | |
1605 | case XS_TIMEOUT: | |
1606 | if(xs->retries-- ) | |
1607 | { | |
1608 | xs->flags &= ~ITSDONE; | |
1609 | goto retry; | |
1610 | } | |
1611 | retval = EIO; | |
1612 | break; | |
1613 | default: | |
1614 | retval = EIO; | |
1615 | printf("cd%d: unknown error category from scsi driver\n" | |
1616 | ,unit); | |
1617 | } | |
1618 | break; | |
1619 | case COMPLETE: | |
1620 | retval = ESUCCESS; | |
1621 | break; | |
1622 | case TRY_AGAIN_LATER: | |
1623 | if(xs->retries-- ) | |
1624 | { | |
1625 | if(tsleep( 0,PRIBIO + 2,"retry",hz * 2)) | |
1626 | { | |
1627 | xs->flags &= ~ITSDONE; | |
1628 | goto retry; | |
1629 | } | |
1630 | } | |
1631 | retval = EIO; | |
1632 | break; | |
1633 | default: | |
1634 | retval = EIO; | |
1635 | } | |
1636 | cd_free_xs(unit,xs,flags); | |
1637 | cdstart(unit); /* check if anything is waiting fr the xs */ | |
1638 | } | |
1639 | else | |
1640 | { | |
1641 | printf("cd%d: not set up\n",unit); | |
1642 | return(EINVAL); | |
1643 | } | |
1644 | return(retval); | |
1645 | } | |
1646 | /***************************************************************\ | |
1647 | * Look at the returned sense and act on the error and detirmine * | |
1648 | * The unix error number to pass back... (0 = report no error) * | |
1649 | \***************************************************************/ | |
1650 | ||
1651 | int cd_interpret_sense(unit,xs) | |
1652 | int unit; | |
1653 | struct scsi_xfer *xs; | |
1654 | { | |
1655 | struct scsi_sense_data *sense; | |
1656 | int key; | |
1657 | int silent; | |
1658 | ||
1659 | /***************************************************************\ | |
1660 | * If the flags say errs are ok, then always return ok. * | |
1661 | \***************************************************************/ | |
1662 | if (xs->flags & SCSI_ERR_OK) return(ESUCCESS); | |
1663 | silent = (xs->flags & SCSI_SILENT); | |
1664 | ||
1665 | sense = &(xs->sense); | |
869c4419 | 1666 | switch(sense->error_code & SSD_ERRCODE) |
15637ed4 | 1667 | { |
869c4419 | 1668 | case 0x70: |
15637ed4 | 1669 | { |
869c4419 | 1670 | key=sense->ext.extended.flags & SSD_KEY; |
15637ed4 RG |
1671 | switch(key) |
1672 | { | |
1673 | case 0x0: | |
1674 | return(ESUCCESS); | |
1675 | case 0x1: | |
1676 | if(!silent) | |
1677 | { | |
98639498 | 1678 | printf("cd%d: soft error(corrected)", unit); |
869c4419 | 1679 | if(sense->error_code & SSD_ERRCODE_VALID) |
15637ed4 | 1680 | { |
98639498 | 1681 | printf(" block no. %d (decimal)", |
15637ed4 RG |
1682 | (sense->ext.extended.info[0] <<24)| |
1683 | (sense->ext.extended.info[1] <<16)| | |
1684 | (sense->ext.extended.info[2] <<8)| | |
1685 | (sense->ext.extended.info[3] )); | |
1686 | } | |
1687 | printf("\n"); | |
1688 | } | |
1689 | return(ESUCCESS); | |
1690 | case 0x2: | |
98639498 | 1691 | if(!silent)printf("cd%d: not ready\n", unit); |
15637ed4 RG |
1692 | return(ENODEV); |
1693 | case 0x3: | |
1694 | if(!silent) | |
1695 | { | |
98639498 | 1696 | printf("cd%d: medium error", unit); |
869c4419 | 1697 | if(sense->error_code & SSD_ERRCODE_VALID) |
15637ed4 | 1698 | { |
98639498 | 1699 | printf(" block no. %d (decimal)", |
15637ed4 RG |
1700 | (sense->ext.extended.info[0] <<24)| |
1701 | (sense->ext.extended.info[1] <<16)| | |
1702 | (sense->ext.extended.info[2] <<8)| | |
1703 | (sense->ext.extended.info[3] )); | |
1704 | } | |
1705 | printf("\n"); | |
1706 | } | |
1707 | return(EIO); | |
1708 | case 0x4: | |
98639498 | 1709 | if(!silent)printf("cd%d: non-media hardware failure\n", |
15637ed4 RG |
1710 | unit); |
1711 | return(EIO); | |
1712 | case 0x5: | |
98639498 | 1713 | if(!silent)printf("cd%d: illegal request\n", |
15637ed4 RG |
1714 | unit); |
1715 | return(EINVAL); | |
1716 | case 0x6: | |
98639498 | 1717 | if(!silent)printf("cd%d: Unit attention\n", unit); |
4f6ede5d RG |
1718 | if (cd_driver->cd_data[unit]->openparts) |
1719 | cd_driver->cd_data[unit]->flags &= ~(CDVALID | CDHAVELABEL); | |
15637ed4 RG |
1720 | { |
1721 | return(EIO); | |
1722 | } | |
1723 | return(ESUCCESS); | |
1724 | case 0x7: | |
1725 | if(!silent) | |
1726 | { | |
98639498 | 1727 | printf("cd%d: attempted protection violation", |
15637ed4 | 1728 | unit); |
869c4419 | 1729 | if(sense->error_code & SSD_ERRCODE_VALID) |
15637ed4 | 1730 | { |
98639498 | 1731 | printf(" block no. %d (decimal)", |
15637ed4 RG |
1732 | (sense->ext.extended.info[0] <<24)| |
1733 | (sense->ext.extended.info[1] <<16)| | |
1734 | (sense->ext.extended.info[2] <<8)| | |
1735 | (sense->ext.extended.info[3] )); | |
1736 | } | |
1737 | printf("\n"); | |
1738 | } | |
1739 | return(EACCES); | |
1740 | case 0x8: | |
1741 | if(!silent) | |
1742 | { | |
98639498 RG |
1743 | printf("cd%d: block wrong state (worm)", |
1744 | unit); | |
869c4419 | 1745 | if(sense->error_code & SSD_ERRCODE_VALID) |
15637ed4 | 1746 | { |
98639498 | 1747 | printf(" block no. %d (decimal)", |
15637ed4 RG |
1748 | (sense->ext.extended.info[0] <<24)| |
1749 | (sense->ext.extended.info[1] <<16)| | |
1750 | (sense->ext.extended.info[2] <<8)| | |
1751 | (sense->ext.extended.info[3] )); | |
1752 | } | |
1753 | printf("\n"); | |
1754 | } | |
1755 | return(EIO); | |
1756 | case 0x9: | |
98639498 | 1757 | if(!silent)printf("cd%d: vendor unique\n", unit); |
15637ed4 RG |
1758 | return(EIO); |
1759 | case 0xa: | |
98639498 | 1760 | if(!silent)printf("cd%d: copy aborted\n", unit); |
15637ed4 RG |
1761 | return(EIO); |
1762 | case 0xb: | |
98639498 | 1763 | if(!silent)printf("cd%d: command aborted\n", unit); |
15637ed4 RG |
1764 | return(EIO); |
1765 | case 0xc: | |
1766 | if(!silent) | |
1767 | { | |
98639498 | 1768 | printf("cd%d: search returned", unit); |
869c4419 | 1769 | if(sense->error_code & SSD_ERRCODE_VALID) |
15637ed4 | 1770 | { |
98639498 | 1771 | printf(" block no. %d (decimal)", |
15637ed4 RG |
1772 | (sense->ext.extended.info[0] <<24)| |
1773 | (sense->ext.extended.info[1] <<16)| | |
1774 | (sense->ext.extended.info[2] <<8)| | |
1775 | (sense->ext.extended.info[3] )); | |
1776 | } | |
1777 | printf("\n"); | |
1778 | } | |
1779 | return(ESUCCESS); | |
1780 | case 0xd: | |
98639498 | 1781 | if(!silent)printf("cd%d: volume overflow\n", unit); |
15637ed4 RG |
1782 | return(ENOSPC); |
1783 | case 0xe: | |
1784 | if(!silent) | |
1785 | { | |
98639498 | 1786 | printf("cd%d: verify miscompare", unit); |
869c4419 | 1787 | if(sense->error_code & SSD_ERRCODE_VALID) |
15637ed4 | 1788 | { |
98639498 | 1789 | printf(" block no. %d (decimal)", |
15637ed4 RG |
1790 | (sense->ext.extended.info[0] <<24)| |
1791 | (sense->ext.extended.info[1] <<16)| | |
1792 | (sense->ext.extended.info[2] <<8)| | |
1793 | (sense->ext.extended.info[3] )); | |
1794 | } | |
1795 | printf("\n"); | |
1796 | } | |
1797 | return(EIO); | |
1798 | case 0xf: | |
98639498 | 1799 | if(!silent)printf("cd%d: unknown error key\n", unit); |
15637ed4 RG |
1800 | return(EIO); |
1801 | } | |
1802 | break; | |
1803 | } | |
869c4419 | 1804 | default: |
15637ed4 | 1805 | { |
98639498 RG |
1806 | if(!silent) |
1807 | { | |
1808 | printf("cd%d: error code %d", | |
1809 | unit, | |
1810 | sense->error_code & SSD_ERRCODE); | |
1811 | if(sense->error_code & SSD_ERRCODE_VALID) | |
1812 | { | |
1813 | printf(" block no. %d (decimal)", | |
1814 | (sense->ext.unextended.blockhi <<16) | |
1815 | + (sense->ext.unextended.blockmed <<8) | |
1816 | + (sense->ext.unextended.blocklow )); | |
1817 | } | |
1818 | printf("\n"); | |
1819 | } | |
15637ed4 RG |
1820 | } |
1821 | return(EIO); | |
1822 | } | |
1823 | } | |
1824 | ||
1825 | ||
1826 | ||
1827 | ||
1828 | int | |
1829 | cdsize(dev_t dev) | |
1830 | { | |
1831 | return (-1); | |
1832 | } | |
1833 | ||
98639498 | 1834 | #if 0 |
15637ed4 RG |
1835 | show_mem(address,num) |
1836 | unsigned char *address; | |
1837 | int num; | |
1838 | { | |
1839 | int x,y; | |
1840 | printf("------------------------------"); | |
1841 | for (y = 0; y<num; y += 1) | |
1842 | { | |
1843 | if(!(y % 16)) | |
1844 | printf("\n%03d: ",y); | |
1845 | printf("%02x ",*address++); | |
1846 | } | |
1847 | printf("\n------------------------------\n"); | |
1848 | } | |
98639498 | 1849 | #endif |