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