Commit | Line | Data |
---|---|---|
15637ed4 RG |
1 | /* |
2 | * Adaptech 1542 SCSI driver for 386bsd | |
3 | * | |
4 | * Pace Willisson pace@blitz.com March 28, 1992 | |
5 | * | |
6 | * Placed in the public domain with NO WARRANTIES, not even the | |
7 | * implied warranties for MERCHANTABILITY or FITNESS FOR A | |
8 | * PARTICULAR PURPOSE. | |
9 | * | |
10 | * | |
11 | * This is a very early version - use with care. | |
12 | * | |
13 | * Here is the config info: | |
14 | * | |
15 | * controller as0 at isa? port 0x330 bio irq 11 drq 5 vector asintr | |
16 | * disk dk6 at as0 drive 0 | |
17 | * | |
18 | * Also, don't forget to update sys/i386/conf/files.i386. | |
19 | * | |
20 | * So far, used with: | |
21 | * | |
22 | * CDC WREN 5 600 Megabyte magnetic disk | |
23 | * EXABYTE EXB-8200 8mm tape drive | |
24 | * SONY CDU-541 cdrom | |
25 | * | |
26 | * The the tape stuff still needs a lot of working concerning | |
27 | * file marks, end of tape handling and rewinding, but I have | |
28 | * extracted tar tapes to a file system mounted on the CDC disk. | |
29 | * | |
30 | * minor number bits: | |
31 | * | |
32 | * 7 6 5 4 3 2 1 0 | |
33 | * +-----+ partition number | |
34 | * +-----+ scsi target number | |
35 | * +--+ unused (should be 0) | |
36 | * | |
37 | * For tape drives, set the partition number to 0 for regular, | |
38 | * 1 for no rewind. | |
39 | * | |
40 | * Only supports LUN 0. | |
41 | * | |
42 | * To use with a read-write disk, first use diskpart to create | |
43 | * a disktab entry, then use disklabel. Since I don't have | |
44 | * the boot programs done yet, I faked it with: | |
45 | * | |
46 | * # cd /usr/mdec | |
47 | * # cp wdboot asboot | |
48 | * # cp bootwd bootas | |
49 | * | |
50 | * Now you can run disklabel, newfs, etc. | |
51 | * | |
52 | * Please send patches and names other perpherials that work to | |
53 | * pace@blitz.com. If you have trouble that you can't fix, please | |
54 | * wait for the next release before contacting me. | |
55 | * | |
56 | * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE | |
57 | * -------------------- ----- ---------------------- | |
58 | * CURRENT PATCH LEVEL: 1 00088 | |
59 | * -------------------- ----- ---------------------- | |
60 | * | |
61 | * 23 Oct 92 Joerg Lohse changed ccb opcode for compatibility | |
62 | * with Adaptec AHA-1542A | |
63 | * 27 Feb 93 James da Silva Tapedrive fixes. | |
64 | */ | |
65 | ||
66 | #include "as.h" | |
67 | #if NAS > 0 | |
68 | ||
69 | #include "param.h" | |
70 | #include "dkbad.h" | |
71 | #include "systm.h" | |
72 | #include "conf.h" | |
73 | #include "file.h" | |
74 | #include "stat.h" | |
75 | #include "ioctl.h" | |
76 | #include "disklabel.h" | |
77 | #include "buf.h" | |
78 | #include "uio.h" | |
79 | #include "i386/isa/isa_device.h" | |
80 | #include "i386/isa/icu.h" | |
81 | #include "syslog.h" | |
82 | #include "vm/vm.h" | |
83 | #include "kernel.h" | |
84 | ||
85 | #include "asreg.h" | |
86 | ||
87 | int asstrategy (); | |
88 | int asabort (); | |
89 | extern int hz; | |
90 | ||
91 | int asverbose = 0; | |
92 | ||
93 | ||
94 | /* target id 7 is the controller itself */ | |
95 | #define NTARGETS 7 | |
96 | ||
97 | struct mailbox_entry mailboxes[NTARGETS * 2] = {0}; | |
98 | ||
99 | #define b_cylin b_resid /* fake cylinder number for disksort */ | |
100 | ||
101 | /* maximum scatter list size for Adaptech controller */ | |
102 | #define NSCATTER 17 | |
103 | ||
104 | /* this array must reside in contiguous physical memory */ | |
105 | struct asinfo { | |
106 | dev_t dev; | |
107 | struct buf requests; | |
108 | struct mailbox_entry *mailbox; | |
109 | int active; | |
110 | struct ccb ccb; | |
111 | unsigned int ccb_phys; | |
112 | char scatter_list[NSCATTER * 6]; | |
113 | ||
114 | struct disklabel label; | |
115 | struct dos_partition dospart[NDOSPART]; | |
116 | int have_label; | |
117 | ||
118 | int scsi_lock; | |
119 | struct buf *scsi_bp; | |
120 | int scsi_cdb_len; | |
121 | unsigned char scsi_cdb[MAXCDB]; | |
122 | ||
123 | int tape; /* sequential */ | |
124 | int disk; /* nonsequential */ | |
125 | int read_only; /* CDROM */ | |
126 | int removable; /* unsupported and tested */ | |
127 | char vendor[9]; | |
128 | char model[17]; | |
129 | char revision[5]; | |
130 | int bs; /* device block size */ | |
131 | ||
132 | int open_lock; | |
133 | int open; | |
134 | int units_open; | |
135 | ||
136 | int wlabel; | |
137 | ||
138 | int retry_count; | |
139 | int start_time; | |
140 | int restart_pending; | |
141 | ||
142 | } asinfo[NTARGETS] = {0}; | |
143 | ||
144 | #define dev_part(dev) (minor (dev) & 7) | |
145 | #define dev_target(dev) ((minor (dev) >> 3) & 7) | |
146 | #define dev_rewind(dev) ((minor (dev) & 1) == 0) | |
147 | ||
148 | #define makeasdev(major, target, part) \ | |
149 | makedev ((major), ((target) << 3) | (part)) | |
150 | ||
151 | int as_port; | |
152 | ||
153 | int asprobe(struct isa_device *), asattach(struct isa_device *), | |
154 | asintr(dev_t); | |
155 | ||
156 | struct isa_driver asdriver = { | |
157 | asprobe, asattach, "as", | |
158 | }; | |
159 | ||
160 | int | |
161 | asprobe (struct isa_device *dvp) | |
162 | { | |
163 | int val; | |
164 | ||
165 | as_port = dvp->id_iobase; | |
166 | ||
167 | outb (as_port + AS_CONTROL, AS_CONTROL_SRST); | |
168 | DELAY (30000); | |
169 | val = inb (as_port + AS_STATUS); | |
170 | ||
171 | if (val == (AS_STATUS_INIT | AS_STATUS_IDLE)) | |
172 | return (1); | |
173 | as_port = 0; | |
174 | return (0); | |
175 | } | |
176 | ||
177 | asattach (struct isa_device *dvp) | |
178 | { | |
179 | int i; | |
180 | unsigned int physaddr; | |
181 | int val; | |
182 | int s; | |
183 | ||
184 | for (i = 0; i < NTARGETS; i++) { | |
185 | asinfo[i].mailbox = &mailboxes[i]; | |
186 | asinfo[i].ccb_phys = vtophys (&asinfo[i].ccb); | |
187 | } | |
188 | ||
189 | isa_dmacascade(dvp->id_drq); | |
190 | ||
191 | physaddr = vtophys (mailboxes); | |
192 | ||
193 | s = splbio (); | |
194 | if (as_put_byte (AS_CMD_MAILBOX_INIT) < 0 | |
195 | || as_put_byte (NTARGETS) < 0 | |
196 | || as_put_byte (physaddr >> 16) < 0 | |
197 | || as_put_byte (physaddr >> 8) < 0 | |
198 | || as_put_byte (physaddr) < 0) { | |
199 | splx (s); | |
200 | return (EIO); | |
201 | } | |
202 | splx (s); | |
203 | DELAY (300); | |
204 | val = inb (as_port + AS_STATUS); | |
205 | ||
206 | if (val & AS_STATUS_INIT) | |
207 | printf ("as: mailbox init error: 0x%x\n", val); | |
208 | } | |
209 | ||
210 | int | |
211 | ascmd (as, bp, direction, count, retrycount) | |
212 | struct asinfo *as; | |
213 | struct buf *bp; | |
214 | int direction; | |
215 | int count; | |
216 | int retrycount; | |
217 | { | |
218 | int err; | |
219 | ||
220 | do { | |
221 | if (asverbose) | |
222 | printf ("ascmd "); | |
223 | bp->b_bcount = count; | |
224 | bp->b_error = 0; | |
225 | bp->b_flags &= ~(B_READ | B_ERROR | B_DONE); | |
226 | if (direction == B_READ) | |
227 | bp->b_flags |= B_READ; | |
228 | ||
229 | bp->b_dev = as->dev; | |
230 | bp->b_blkno = 0; | |
231 | ||
232 | as->scsi_bp = bp; | |
233 | /* scsi_cdb, scsi_cdb_len set up by caller */ | |
234 | ||
235 | asstrategy (bp); | |
236 | err = biowait (bp); | |
237 | as->scsi_bp = NULL; | |
238 | ||
239 | } while (err && --retrycount); | |
240 | ||
241 | return (err); | |
242 | } | |
243 | ||
244 | asstring (dest, src, size) | |
245 | char *dest; | |
246 | char *src; | |
247 | int size; | |
248 | { | |
249 | size--; | |
250 | bcopy (src, dest, size); | |
251 | while (size > 0 && dest[size - 1] == ' ') | |
252 | size--; | |
253 | dest[size] = 0; | |
254 | } | |
255 | ||
256 | asopen (dev, flag) | |
257 | dev_t dev; | |
258 | int flag; | |
259 | { | |
260 | struct asinfo *as; | |
261 | unsigned int physaddr; | |
262 | struct buf *bp = NULL; | |
263 | int retry; | |
264 | unsigned char *cdb; | |
265 | char *p, *q; | |
266 | int n; | |
267 | int error; | |
268 | char vendor[9]; | |
269 | char model[17]; | |
270 | int disksize; | |
271 | ||
272 | if (as_port == 0 || dev_target (dev) >= NTARGETS) | |
273 | return (ENXIO); | |
274 | ||
275 | as = &asinfo[dev_target (dev)]; | |
276 | as->dev = dev; | |
277 | ||
278 | while (as->open_lock) | |
279 | if (error = tsleep ((caddr_t)as, PZERO|PCATCH, "scsiopen", 0)) | |
280 | return (error); | |
281 | ||
282 | if (as->open) { | |
283 | if (as->tape) | |
284 | return (EBUSY); | |
285 | ||
286 | if (as->have_label == 0 && dev_part (dev) != 3) | |
287 | return (ENXIO); | |
288 | ||
289 | as->units_open |= 1 << dev_part (dev); | |
290 | return (0); | |
291 | } | |
292 | ||
293 | as->open_lock = 1; | |
294 | ||
295 | /* it seems like we might have to block here in case someone | |
296 | * opens the device just after someone else closes | |
297 | */ | |
298 | while (as->scsi_lock) | |
299 | if (error = tsleep ((caddr_t)as, PZERO|PCATCH, "scsicmd", 0)) | |
300 | return (error); | |
301 | ||
302 | as->scsi_lock = 1; | |
303 | ||
304 | error = EIO; | |
305 | ||
306 | as->have_label = 0; | |
307 | as->tape = 0; | |
308 | as->disk = 0; | |
309 | as->read_only = 0; | |
310 | as->removable = 0; | |
311 | bcopy(as->vendor, vendor, sizeof(vendor)); | |
312 | bcopy(as->model, model, sizeof(model)); | |
313 | as->vendor[0] = 0; | |
314 | as->model[0] = 0; | |
315 | as->revision[0] = 0; | |
316 | ||
317 | bp = geteblk (DEV_BSIZE); | |
318 | ||
319 | if (asverbose) { | |
320 | printf ("openbuf = 0x%x phys 0x%x\n", | |
321 | bp->b_un.b_addr, vtophys (bp->b_un.b_addr)); | |
322 | printf ("mailboxes = 0x%x\n", mailboxes); | |
323 | } | |
324 | ||
325 | /* first, find out if a device is present, and just what it is */ | |
326 | as->scsi_cdb_len = 6; | |
327 | cdb = as->scsi_cdb; | |
328 | bzero (cdb, 6); | |
329 | cdb[0] = 0x12; /* INQUIRY */ | |
330 | cdb[4] = 255; /* allocation length */ | |
331 | if (error = ascmd (as, bp, B_READ, DEV_BSIZE, 2)) | |
332 | /* does not respond to inquiry, obviously not CCS, give up */ | |
333 | goto done; | |
334 | ||
335 | ||
336 | /* blather on console about it */ | |
337 | p = bp->b_un.b_addr; | |
338 | if (asverbose) { | |
339 | printf ("inquiry: "); | |
340 | for (n = 0; n < 20; n++) | |
341 | printf ("%x ", p[n] & 0xff); | |
342 | printf ("\n"); | |
343 | for (n = 0; n < 40; n++) { | |
344 | if (p[n] >= ' ' && p[n] < 0177) | |
345 | printf ("%c", p[n]); | |
346 | else | |
347 | printf ("."); | |
348 | } | |
349 | printf ("\n"); | |
350 | } | |
351 | ||
352 | switch (p[0]) { | |
353 | case 0: /* normal disk */ | |
354 | case 4: /* write once disk */ | |
355 | as->disk = 1; | |
356 | break; | |
357 | case 5: /* read only disk */ | |
358 | as->read_only = 1; | |
359 | as->disk = 1; | |
360 | break; | |
361 | case 1: /* tape */ | |
362 | as->tape = 1; | |
363 | break; | |
364 | case 0x7f: | |
365 | printf ("logical unit not present\n"); | |
366 | goto done; | |
367 | default: | |
368 | printf ("unknown peripheral device type: 0x%x\n", p[0]); | |
369 | goto done; | |
370 | } | |
371 | ||
372 | as->removable = (p[1] & 0x80) ? 1 : 0; | |
373 | ||
374 | n = p[4] & 0xff; | |
375 | if (n >= 31) { | |
376 | asstring (as->vendor, p + 8, sizeof as->vendor); | |
377 | asstring (as->model, p + 16, sizeof as->model); | |
378 | asstring (as->revision, p + 32, sizeof as->revision); | |
379 | } | |
380 | ||
381 | if(bcmp(as->vendor,vendor, sizeof(vendor)) != 0 || | |
382 | bcmp(as->model,model, sizeof(model)) != 0) { | |
383 | printf("as%d: attached tgt %d <%s %s %s> ", 0, dev_target(dev), | |
384 | as->vendor, as->model, as->revision); | |
385 | if (as->read_only) printf("readonly "); | |
386 | if (!as->removable) printf("winchester "); | |
387 | if (as->tape) printf("tape "); | |
388 | if (as->disk) printf("disk "); | |
389 | printf("\n"); | |
390 | } | |
391 | ||
392 | /* probe for desired block size */ | |
393 | ||
394 | /* assume default of 512, except if CDROM (2048) */ | |
395 | if (as->read_only) | |
396 | as->bs = 2048; | |
397 | else | |
398 | as->bs = 512; | |
399 | ||
400 | bzero(cdb, 6); | |
401 | cdb[0] = 0x1A; /* SCSI_MDSENSE */ | |
402 | cdb[4] = 255; | |
403 | if (as->tape && ascmd (as, bp, B_READ, 12, 2) == 0) { | |
404 | int minblk, maxblk; | |
405 | ||
406 | #ifdef notdef | |
407 | /* blather about device more */ | |
408 | if(bcmp(as->vendor,vendor, sizeof(vendor)) != 0 || | |
409 | bcmp(as->model,model, sizeof(model)) != 0) { | |
410 | p = bp->b_un.b_addr; | |
411 | printf("as%d: data len %d medium %d speed/bufmode 0x%x desc len %d\n", | |
412 | dev_target(dev), p[0], p[1], p[2], p[3]); | |
413 | printf("as%d: density %d nblocks %d block len %d\n", | |
414 | dev_target(dev), p[4], | |
415 | (long)p[5]*65536+p[6]*256+p[7], | |
416 | (long)p[9]*65536+p[10]*256+p[11]); | |
417 | } | |
418 | #endif | |
419 | ||
420 | /* obtain possible block sizes */ | |
421 | bzero(cdb, 6); | |
422 | cdb[0] = 0x05; /* SCSI_RDLIMITS; */ | |
423 | if (ascmd (as, bp, B_READ, 12, 2) == 0) { | |
424 | p = bp->b_un.b_addr; | |
425 | minblk = p[4]*256+p[5]; | |
426 | maxblk = p[1]*65536+p[2]*256+p[3]; | |
427 | #ifdef notdef | |
428 | if(bcmp(as->vendor,vendor, sizeof(vendor)) != 0 || | |
429 | bcmp(as->model,model, sizeof(model)) != 0) { | |
430 | printf("as%d: limits: min block len %ld max block len %ld\n", | |
431 | dev_target(dev), minblk, maxblk); | |
432 | } | |
433 | #endif | |
434 | if ( minblk == maxblk ) | |
435 | as->bs = minblk; | |
436 | else if (as->tape) | |
437 | as->bs = 1; | |
438 | } | |
439 | } | |
440 | ||
441 | as->scsi_cdb_len = 10; | |
442 | bzero(cdb, 10); | |
443 | cdb[0] = 0x25; /* SCSI_READCAPACITY */ | |
444 | disksize = 0; | |
445 | if (as->disk && ascmd (as, bp, B_READ, 12, 2) == 0) { | |
446 | p = bp->b_un.b_addr; | |
447 | disksize = ntohl(*(long *)p); | |
448 | as->bs = ntohl(*(long *)(p+4)); | |
449 | ||
450 | } | |
451 | ||
452 | if(asverbose) | |
453 | printf("block size %d disksize %d ", as->bs, disksize); | |
454 | ||
455 | ||
456 | /* for standard disk, negotiate block size */ | |
457 | if (as->read_only == 0 && as->disk) { | |
458 | /* do mode select to set the logical block size */ | |
459 | as->scsi_cdb_len = 6; | |
460 | cdb = as->scsi_cdb; | |
461 | bzero (cdb, 6); | |
462 | cdb[0] = 0x15; /* MODE SELECT */ | |
463 | cdb[4] = 12; /* parameter list length */ | |
464 | ||
465 | p = bp->b_un.b_addr; | |
466 | bzero (p, 12); | |
467 | p[3] = 8; /* block descriptor length */ | |
468 | n = as->bs == 1 ? 0 : as->bs; | |
469 | p[9] = n >> 16; | |
470 | p[10] = n >> 8; | |
471 | p[11] = n; | |
472 | ||
473 | (void) ascmd (as, bp, B_WRITE, 12, 2); | |
474 | } | |
475 | ||
476 | /* device online and ready? */ | |
477 | as->scsi_cdb_len = 6; | |
478 | bzero(cdb, 6); | |
479 | cdb[0] = 0x00; /* SCSI_UNITRDY */ | |
480 | if (error = ascmd (as, bp, B_READ, 12, 2)) { | |
481 | printf("as%d: drive not online\n", dev_target(dev)); | |
482 | goto done; | |
483 | } | |
484 | ||
485 | if (as->disk && as->read_only == 0) { | |
486 | /* read disk label */ | |
487 | bzero ((caddr_t)&as->label, sizeof as->label); | |
488 | as->label.d_secsize = as->bs; | |
489 | as->label.d_secpercyl = 64*32; | |
490 | as->label.d_type = DTYPE_SCSI; | |
491 | ||
492 | ||
493 | /* read label using "d" partition */ | |
494 | if ((p = readdisklabel ( | |
495 | makeasdev (major (dev), dev_target (dev), 3), | |
496 | asstrategy, &as->label, as->dospart, 0, 0)) == NULL){ | |
497 | as->have_label = 1; | |
498 | } else { | |
499 | if (disksize) { | |
500 | as->label.d_subtype = DSTYPE_GEOMETRY; | |
501 | as->label.d_npartitions = 3; | |
502 | /* partition 0 holds bios, partition 1 ESDI */ | |
503 | as->label.d_partitions[2].p_size = disksize; | |
504 | as->label.d_partitions[2].p_offset = 0; | |
505 | } | |
506 | if (asverbose || dev_part (dev) != 3) | |
507 | printf ("error reading label: %s\n", p); | |
508 | if (dev_part (dev) != 3) { | |
509 | error = EINVAL; | |
510 | goto done; | |
511 | } | |
512 | } | |
513 | } | |
514 | ||
515 | /* may want to set logical block size here ? */ | |
516 | error = 0; | |
517 | ||
518 | done: | |
519 | if (bp) { | |
520 | bp->b_flags |= B_INVAL | B_AGE; | |
521 | brelse (bp); | |
522 | } | |
523 | ||
524 | if (error == 0) | |
525 | as->open = 1; | |
526 | ||
527 | as->open_lock = 0; | |
528 | as->scsi_lock = 0; | |
529 | wakeup (as); | |
530 | ||
531 | return (error); | |
532 | } | |
533 | ||
534 | asclose (dev, flag) | |
535 | dev_t dev; | |
536 | { | |
537 | struct asinfo *as; | |
538 | int error = 0; | |
539 | unsigned char *cdb; | |
540 | struct buf *bp; | |
541 | int n; | |
542 | ||
543 | as = &asinfo[dev_target (dev)]; | |
544 | ||
545 | while (as->open_lock) | |
546 | if (error = tsleep ((caddr_t)as, PZERO|PCATCH, "scsiclose", 0)) | |
547 | return (error); | |
548 | ||
549 | as->open_lock = 1; | |
550 | ||
551 | if (as->tape) { | |
552 | while (as->scsi_lock) | |
553 | if (error = tsleep ((caddr_t)as, PZERO|PCATCH, | |
554 | "scsicmd", 0)) | |
555 | return (error); | |
556 | ||
557 | as->scsi_lock = 1; | |
558 | ||
559 | bp = geteblk (DEV_BSIZE); | |
560 | ||
561 | if ((flag & FWRITE) != 0) { | |
562 | /* presume user will use tape again */ | |
563 | as->scsi_cdb_len = 6; | |
564 | cdb = as->scsi_cdb; | |
565 | bzero (cdb, 6); | |
566 | cdb[0] = 0x10; /* write filemarks */ | |
567 | cdb[4] = 1; /* one of them */ | |
568 | error = ascmd (as, bp, B_READ, 0, 1); | |
569 | } | |
570 | if (dev_rewind (dev) || error) { | |
571 | if ( error == 0 && (flag & FWRITE) != 0) { | |
572 | /* presumption error correction */ | |
573 | as->scsi_cdb_len = 6; | |
574 | cdb = as->scsi_cdb; | |
575 | bzero (cdb, 6); | |
576 | cdb[0] = 0x10; /* write filemarks */ | |
577 | cdb[4] = 1; /* one of them */ | |
578 | error |= ascmd (as, bp, B_READ, 0, 1); | |
579 | } | |
580 | as->scsi_cdb_len = 6; | |
581 | cdb = as->scsi_cdb; | |
582 | bzero (cdb, 6); | |
583 | cdb[0] = 0x1; /* rewind */ | |
584 | cdb[1] = 1; /* don't wait until done */ | |
585 | error |= ascmd (as, bp, B_READ, 0, 1); | |
586 | } | |
587 | #ifdef notdef | |
588 | } else { | |
589 | cdb[0] = 0x11; /* backspace */ | |
590 | cdb[1] = 1; /* look at filemarks (instead of blocks) */ | |
591 | n = -1; | |
592 | cdb[2] = n >> 16; | |
593 | cdb[3] = n >> 8; | |
594 | cdb[4] = n; | |
595 | error = ascmd (as, bp, B_READ, 0, 1); | |
596 | } | |
597 | #endif | |
598 | ||
599 | bp->b_flags |= B_INVAL | B_AGE; | |
600 | brelse (bp); | |
601 | ||
602 | as->scsi_lock = 0; | |
603 | } | |
604 | ||
605 | as->units_open &= ~(1 << dev_part (dev)); | |
606 | ||
607 | if (as->units_open == 0) | |
608 | as->open = 0; | |
609 | ||
610 | as->open_lock = 0; | |
611 | ||
612 | wakeup (as); | |
613 | ||
614 | return (error); | |
615 | } | |
616 | ||
617 | int | |
618 | asioctl (dev, cmd, addr, flag) | |
619 | dev_t dev; | |
620 | int cmd; | |
621 | caddr_t addr; | |
622 | int flag; | |
623 | { | |
624 | struct scsicmd *cmdp; | |
625 | struct asinfo *as; | |
626 | int ccblen; | |
627 | struct buf *bp; | |
628 | int error = 0; | |
629 | int direction; | |
630 | struct disklabel *dl; | |
631 | int old_wlabel; | |
632 | ||
633 | as = &asinfo[dev_target (dev)]; | |
634 | ||
635 | switch (cmd) { | |
636 | case DIOCGDINFO: | |
637 | *(struct disklabel *)addr = as->label; | |
638 | break; | |
639 | ||
640 | case DIOCSDINFO: | |
641 | if ((flag & FWRITE) == 0) { | |
642 | error = EBADF; | |
643 | break; | |
644 | } | |
645 | dl = (struct disklabel *)addr; | |
646 | if (error = setdisklabel(&as->label, dl, 0, as->dospart)) | |
647 | break; | |
648 | as->have_label = 1; | |
649 | break; | |
650 | ||
651 | case DIOCWLABEL: | |
652 | if ((flag & FWRITE) == 0) { | |
653 | error = EBADF; | |
654 | break; | |
655 | } | |
656 | as->wlabel = *(int *)addr; | |
657 | break; | |
658 | ||
659 | case DIOCWDINFO: | |
660 | if ((flag & FWRITE) == 0) { | |
661 | error = EBADF; | |
662 | break; | |
663 | } | |
664 | ||
665 | dl = (struct disklabel *)addr; | |
666 | ||
667 | if (error = setdisklabel (&as->label, dl, 0, as->dospart)) | |
668 | break; | |
669 | ||
670 | as->have_label = 1; | |
671 | ||
672 | old_wlabel = as->wlabel; | |
673 | as->wlabel = 1; | |
674 | error = writedisklabel(dev, asstrategy, &as->label, | |
675 | as->dospart); | |
676 | as->wlabel = old_wlabel; | |
677 | break; | |
678 | ||
679 | case SCSICMD: | |
680 | cmdp = (struct scsicmd *)addr; | |
681 | ||
682 | /* limited by max sizeof of geteblk */ | |
683 | if (cmdp->datalen >= 8192 | |
684 | || cmdp->cdblen >= MAXCDB) { | |
685 | error = EINVAL; | |
686 | break; | |
687 | } | |
688 | ||
689 | ccblen = cmdp->ccblen; | |
690 | if (ccblen > sizeof (struct ccb)) | |
691 | ccblen = sizeof (struct ccb); | |
692 | ||
693 | while (as->scsi_lock) | |
694 | if (error = tsleep ((caddr_t)as, PZERO|PCATCH, | |
695 | "scsicmd", 0)) | |
696 | break; | |
697 | ||
698 | as->scsi_lock = 1; | |
699 | ||
700 | bp = geteblk (cmdp->datalen); | |
701 | ||
702 | as->scsi_cdb_len = cmdp->cdblen; | |
703 | if (error = copyin (cmdp->cdb, as->scsi_cdb, cmdp->cdblen)) | |
704 | goto done; | |
705 | ||
706 | direction = cmdp->readflag ? B_READ : B_WRITE; | |
707 | ||
708 | if (direction == B_WRITE) | |
709 | if (error = copyin (cmdp->data, | |
710 | bp->b_un.b_addr, cmdp->datalen)) | |
711 | goto done; | |
712 | ||
713 | ascmd (as, bp, direction, cmdp->datalen, 1); | |
714 | ||
715 | copyout (&as->ccb, cmdp->ccb, ccblen); | |
716 | if (direction == B_READ) | |
717 | copyout (bp->b_un.b_addr, cmdp->data, cmdp->datalen); | |
718 | done: | |
719 | bp->b_flags |= B_INVAL | B_AGE; | |
720 | brelse (bp); | |
721 | as->scsi_lock = 0; | |
722 | wakeup (as); | |
723 | break; | |
724 | default: | |
725 | error = ENOTTY; | |
726 | break; | |
727 | } | |
728 | return (error); | |
729 | } | |
730 | ||
731 | int | |
732 | asstrategy (bp) | |
733 | struct buf *bp; | |
734 | { | |
735 | struct asinfo *as; | |
736 | int s; | |
737 | ||
738 | if (asverbose) | |
739 | printf ("asstrategy %d %d ", bp->b_blkno, bp->b_bcount); | |
740 | s = splbio (); | |
741 | ||
742 | as = &asinfo[dev_target (bp->b_dev)]; | |
743 | ||
744 | if (as->tape) { | |
745 | bp->av_forw = NULL; | |
746 | if (as->requests.b_actf) | |
747 | as->requests.b_actl->av_forw = bp; | |
748 | else | |
749 | as->requests.b_actf = bp; | |
750 | as->requests.b_actl = bp; | |
751 | } else { | |
752 | if (bp != as->scsi_bp | |
753 | && as->have_label == 0 | |
754 | && dev_part (bp->b_dev) != 3) | |
755 | goto bad; | |
756 | ||
757 | bp->b_cylin = bp->b_blkno; | |
758 | disksort (&as->requests, bp); | |
759 | } | |
760 | ||
761 | if (as->active == 0) | |
762 | asstart (as); | |
763 | ||
764 | splx (s); | |
765 | return; | |
766 | ||
767 | bad: | |
768 | bp->b_flags |= B_ERROR; | |
769 | biodone (bp); | |
770 | } | |
771 | ||
772 | asrestart (as) | |
773 | struct asinfo *as; | |
774 | { | |
775 | int s; | |
776 | s = splbio (); | |
777 | as->restart_pending = 0; | |
778 | as->retry_count++; | |
779 | asstart (as); | |
780 | splx (s); | |
781 | } | |
782 | ||
783 | asstart (as) | |
784 | struct asinfo *as; | |
785 | { | |
786 | struct buf *bp; | |
787 | int blknum; | |
788 | unsigned int physaddr; | |
789 | struct ccb *ccb; | |
790 | unsigned char *cdb; | |
791 | int target; | |
792 | char *p; | |
793 | int n; | |
794 | char *sp; | |
795 | int nscatter; | |
796 | int thistime; | |
797 | int nbytes; | |
798 | struct partition *part; | |
799 | int blkno; | |
800 | int nblocks; | |
801 | int total; | |
802 | int bs = as->bs; | |
803 | ||
804 | ||
805 | if (as->restart_pending) { | |
806 | as->restart_pending = 0; | |
807 | untimeout (asrestart, as); | |
808 | } | |
809 | ||
810 | again: | |
811 | if ((bp = as->requests.b_actf) == NULL) | |
812 | return; | |
813 | ||
814 | bp->b_error = 0; | |
815 | ||
816 | if (asverbose) | |
817 | printf ("asstart %x ", bp); | |
818 | ||
819 | if (as->mailbox->cmd != 0) { | |
820 | /* this can't happen, unless the card flakes */ | |
821 | printf ("asstart: mailbox not available\n"); | |
822 | bp->b_error = EIO; | |
823 | goto bad; | |
824 | } | |
825 | ||
826 | if (as->retry_count == 0) { | |
827 | as->start_time = time.tv_sec; | |
828 | } else { | |
829 | if (time.tv_sec - as->start_time > 60) { | |
830 | printf ("as: command timed out\n"); | |
831 | bp->b_error = EIO; | |
832 | goto done; | |
833 | } | |
834 | } | |
835 | ||
836 | if (bp != as->scsi_bp) { | |
837 | if (bp->b_bcount == 0) | |
838 | goto done; | |
839 | ||
840 | if ((bp->b_bcount % bs) != 0) { | |
841 | printf("as: partial block read\n"); | |
842 | bp->b_error = EIO; | |
843 | goto bad; | |
844 | } | |
845 | } | |
846 | ||
847 | if (bp != as->scsi_bp) { | |
848 | ||
849 | blkno = bp->b_blkno; | |
850 | nblocks = bp->b_bcount / bs; | |
851 | ||
852 | if (as->have_label && dev_part(bp->b_dev) != 3) { | |
853 | part = &as->label.d_partitions[dev_part (bp->b_dev)]; | |
854 | ||
855 | if (blkno > part->p_size) { | |
856 | bp->b_error = EINVAL; | |
857 | goto bad; | |
858 | } | |
859 | if (blkno == part->p_size) { | |
860 | bp->b_resid = bp->b_bcount; | |
861 | goto done; | |
862 | } | |
863 | ||
864 | if (blkno + nblocks >= part->p_size) | |
865 | nblocks = part->p_size - blkno; | |
866 | ||
867 | blkno += part->p_offset; | |
868 | } else | |
869 | blkno = (blkno * DEV_BSIZE)/bs; | |
870 | if(asverbose) | |
871 | printf("trans %d ", blkno); | |
872 | if (nblocks > 255) | |
873 | nblocks = 255; | |
874 | total = nblocks * bs; | |
875 | if(asverbose) | |
876 | printf("total %d nblocks %d ", total, nblocks); | |
877 | /*bp->b_bcount = total; /* XXX partial tape block read - wrong */ | |
878 | } else { | |
879 | #ifdef nomore | |
880 | if (as->fixed == 0) { | |
881 | total = bp->b_bcount; | |
882 | } else { | |
883 | total = bp->b_bcount; | |
884 | blkno = bp->b_blkno; | |
885 | nblocks = bp->b_bcount / as->fixed; | |
886 | } | |
887 | #else | |
888 | total = bp->b_bcount; | |
889 | #endif | |
890 | } | |
891 | ||
892 | p = bp->b_un.b_addr; | |
893 | n = 0; | |
894 | sp = as->scatter_list; | |
895 | nscatter = 0; | |
896 | if (as->tape && as->bs == 1) | |
897 | total = bp->b_bcount; | |
898 | while (n < total && nscatter < NSCATTER) { | |
899 | thistime = page_size - ((vm_offset_t)p - trunc_page (p)); | |
900 | ||
901 | if (n + thistime > total) | |
902 | thistime = total - n; | |
903 | ||
904 | physaddr = vtophys (p); | |
905 | ||
906 | if (asverbose) | |
907 | printf ("%d bytes to %x (%x)\n", | |
908 | thistime, p, physaddr); | |
909 | sp[0] = thistime >> 16; | |
910 | sp[1] = thistime >> 8; | |
911 | sp[2] = thistime; | |
912 | sp[3] = physaddr >> 16; | |
913 | sp[4] = physaddr >> 8; | |
914 | sp[5] = physaddr; | |
915 | ||
916 | p += thistime; | |
917 | n += thistime; | |
918 | sp += 6; | |
919 | nscatter++; | |
920 | } | |
921 | ||
922 | if (nscatter == NSCATTER) { | |
923 | printf("out of range, cannot happen?"); | |
924 | bp->b_error = ENXIO; | |
925 | goto bad; | |
926 | } | |
927 | ||
928 | ccb = &as->ccb; | |
929 | ||
930 | /* this only needed to make debugging easier */ | |
931 | bzero ((caddr_t)ccb, sizeof *ccb); | |
932 | ||
933 | if (nscatter) | |
934 | ccb->ccb_opcode = 2; /* scatter cmd, return resid */ | |
935 | else | |
936 | ccb->ccb_opcode = 0; | |
937 | target = dev_target (bp->b_dev); | |
938 | ccb->ccb_addr_and_control = target << 5; | |
939 | if (bp->b_bcount != 0) | |
940 | ccb->ccb_addr_and_control |= (bp->b_flags & B_READ) ? 8 : 0x10; | |
941 | else | |
942 | ccb->ccb_addr_and_control |= 0x18; | |
943 | ||
944 | nbytes = nscatter * 6; | |
945 | ccb->ccb_data_len_msb = nbytes >> 16; | |
946 | ccb->ccb_data_len_mid = nbytes >> 8; | |
947 | ccb->ccb_data_len_lsb = nbytes; | |
948 | ||
949 | ccb->ccb_requst_sense_allocation_len = MAXSENSE; | |
950 | ||
951 | physaddr = vtophys (as->scatter_list); | |
952 | ccb->ccb_data_ptr_msb = physaddr >> 16; | |
953 | ccb->ccb_data_ptr_mid = physaddr >> 8; | |
954 | ccb->ccb_data_ptr_lsb = physaddr; | |
955 | ||
956 | ccb->ccb_link_msb = 0; | |
957 | ccb->ccb_link_mid = 0; | |
958 | ccb->ccb_link_lsb = 0; | |
959 | ccb->ccb_link_id = 0; | |
960 | ccb->ccb_host_status = 0; | |
961 | ccb->ccb_target_status = 0; | |
962 | ccb->ccb_zero1 = 0; | |
963 | ccb->ccb_zero2 = 0; | |
964 | ||
965 | cdb = ccb->ccb_cdb; | |
966 | if (bp == as->scsi_bp) { | |
967 | ccb->ccb_scsi_command_len = as->scsi_cdb_len; | |
968 | bcopy (as->scsi_cdb, cdb, as->scsi_cdb_len); | |
969 | } else if (as->tape) { | |
970 | ccb->ccb_scsi_command_len = 6; | |
971 | cdb[0] = (bp->b_flags & B_READ) ? 8 : 0xa; | |
972 | if (as->bs == 1) { | |
973 | cdb[1] = 0; /* logical unit 0, variable block size */ | |
974 | cdb[2] = bp->b_bcount >> 16; | |
975 | cdb[3] = bp->b_bcount >> 8; | |
976 | cdb[4] = bp->b_bcount; | |
977 | } else { | |
978 | cdb[1] = 1; /* fixed block size */ | |
979 | cdb[2] = nblocks >> 16; | |
980 | cdb[3] = nblocks >> 8; | |
981 | cdb[4] = nblocks; | |
982 | } | |
983 | cdb[5] = 0; /* control byte (used in linking) */ | |
984 | } else { | |
985 | ccb->ccb_scsi_command_len = 10; | |
986 | cdb[0] = (bp->b_flags & B_READ) ? 0x28 : 0x2a; | |
987 | cdb[1] = 0; | |
988 | *(long *) (cdb+2) = htonl(blkno); | |
989 | *(short *) (cdb+7) = htons(nblocks); | |
990 | cdb[9] = 0; /* control byte (used in linking) */ | |
991 | } | |
992 | ||
993 | #ifdef notdef | |
994 | if (asverbose) { | |
995 | printf ("ccb: "); | |
996 | for (n = 0; n < 48; n++) | |
997 | printf ("%02x ", ((unsigned char *)ccb)[n]); | |
998 | printf ("\n"); | |
999 | } | |
1000 | #endif | |
1001 | ||
1002 | physaddr = vtophys (ccb); | |
1003 | as->mailbox->msb = physaddr >> 16; | |
1004 | as->mailbox->mid = physaddr >> 8; | |
1005 | as->mailbox->lsb = physaddr; | |
1006 | as->mailbox->cmd = 1; | |
1007 | ||
1008 | /* tell controller to look in its mailbox */ | |
1009 | as_put_byte (AS_CMD_START_SCSI_COMMAND); | |
1010 | as->active = 1; | |
1011 | timeout (asabort, as, hz * 60 * 2); | |
1012 | return; | |
1013 | ||
1014 | bad: | |
1015 | bp->b_flags |= B_ERROR; | |
1016 | done: | |
1017 | asdone (as, 0); | |
1018 | goto again; | |
1019 | } | |
1020 | ||
1021 | asabort (as) | |
1022 | struct asinfo *as; | |
1023 | { | |
1024 | int s; | |
1025 | int physaddr; | |
1026 | struct buf *bp; | |
1027 | ||
1028 | s = splbio (); | |
1029 | if (as->active) { | |
1030 | printf ("asabort %d\n", as - asinfo); | |
1031 | physaddr = vtophys (&as->ccb); | |
1032 | as->mailbox->msb = physaddr >> 16; | |
1033 | as->mailbox->mid = physaddr >> 8; | |
1034 | as->mailbox->lsb = physaddr; | |
1035 | as->mailbox->cmd = 2; | |
1036 | as_put_byte (AS_CMD_START_SCSI_COMMAND); | |
1037 | ||
1038 | as->active = 0; | |
1039 | bp = as->requests.b_actf; | |
1040 | if (bp) { | |
1041 | bp->b_flags |= B_ERROR; | |
1042 | asdone (as, 1); | |
1043 | } | |
1044 | } | |
1045 | splx (s); | |
1046 | } | |
1047 | ||
1048 | asintr (dev_t dev) | |
1049 | { | |
1050 | int didwork; | |
1051 | int i, j; | |
1052 | struct mailbox_entry *mp; | |
1053 | unsigned int physaddr; | |
1054 | int val; | |
1055 | ||
1056 | outb (as_port + AS_CONTROL, AS_CONTROL_IRST); | |
1057 | #ifdef notdef | |
1058 | if (asverbose) | |
1059 | printf ("asintr %x ", cpl); | |
1060 | #endif | |
1061 | again: | |
1062 | didwork = 0; | |
1063 | for (i = NTARGETS; i < NTARGETS * 2; i++) { | |
1064 | mp = &mailboxes[i]; | |
1065 | ||
1066 | if ((val = mp->cmd) == 0) | |
1067 | continue; | |
1068 | ||
1069 | didwork = 1; | |
1070 | ||
1071 | physaddr = (mp->msb << 16) | |
1072 | | (mp->mid << 8) | |
1073 | | mp->lsb; | |
1074 | ||
1075 | for (j = 0; j < NTARGETS; j++) { | |
1076 | if (asinfo[j].ccb_phys == physaddr) { | |
1077 | mp->cmd = 0; | |
1078 | asintr1 (&asinfo[j], val); | |
1079 | break; | |
1080 | } | |
1081 | } | |
1082 | if (j == NTARGETS) { | |
1083 | printf ("as: unknown mailbox paddr 0x%x\n", physaddr); | |
1084 | mp->cmd = 0; | |
1085 | } | |
1086 | } | |
1087 | ||
1088 | if (didwork) | |
1089 | goto again; | |
1090 | } | |
1091 | ||
1092 | asintr1 (as, val) | |
1093 | struct asinfo *as; | |
1094 | int val; | |
1095 | { | |
1096 | struct buf *bp; | |
1097 | struct ccb *ccb; | |
1098 | int n; | |
1099 | int bad; | |
1100 | char *msg; | |
1101 | char msgbuf[100]; | |
1102 | unsigned char *sp; | |
1103 | int i,key; | |
1104 | ||
1105 | if (asverbose) | |
1106 | printf ("asintr1 %x ", val); | |
1107 | if (as->active == 0) { | |
1108 | printf ("as: stray intr 0x%x\n", as->dev); | |
1109 | return; | |
1110 | } | |
1111 | ||
1112 | as->active = 0; | |
1113 | untimeout (asabort, as); | |
1114 | ||
1115 | bp = as->requests.b_actf; | |
1116 | ccb = &as->ccb; | |
1117 | ||
1118 | if (bp == as->scsi_bp) { | |
1119 | /* no fancy error recovery in this case */ | |
1120 | if (asverbose) | |
1121 | printf ("asintr1:scsicmd "); | |
1122 | #if 0 | |
1123 | if (val != 1) | |
1124 | bp->b_flags |= B_ERROR; | |
1125 | goto next; | |
1126 | #endif | |
1127 | } | |
1128 | ||
1129 | bad = 0; | |
1130 | msg = NULL; | |
1131 | ||
1132 | if (val != 1 && val != 4) { | |
1133 | bad = 1; | |
1134 | sprintf (msgbuf, "funny mailbox message 0x%x\n", val); | |
1135 | msg = msgbuf; | |
1136 | goto wrapup; | |
1137 | } | |
1138 | ||
1139 | if (ccb->ccb_host_status != 0) { | |
1140 | bad = 1; | |
1141 | sprintf (msgbuf, "controller error 0x%x", | |
1142 | ccb->ccb_host_status); | |
1143 | msg = msgbuf; | |
1144 | goto wrapup; | |
1145 | } | |
1146 | ||
1147 | if (ccb->ccb_target_status == 0) | |
1148 | /* good transfer */ | |
1149 | goto wrapup; | |
1150 | ||
1151 | if (ccb->ccb_target_status == 8) { | |
1152 | /* target rejected command because it is busy | |
1153 | * and wants us to try again later. We'll wait 1 second | |
1154 | */ | |
1155 | as->restart_pending = 1; | |
1156 | timeout (asrestart, as, hz); | |
1157 | return; | |
1158 | } | |
1159 | ||
1160 | if (ccb->ccb_target_status != 2) { | |
1161 | bad = 1; | |
1162 | sprintf (msgbuf, "target error 0x%x", | |
1163 | ccb->ccb_target_status); | |
1164 | msg = msgbuf; | |
1165 | goto wrapup; | |
1166 | } | |
1167 | ||
1168 | /* normal path for errors */ | |
1169 | ||
1170 | sp = ccb_sense (ccb); | |
1171 | /* check for extended sense information */ | |
1172 | if ((sp[0] & 0x7f) != 0x70) { | |
1173 | /* none */ | |
1174 | bad = 1; | |
1175 | sprintf (msgbuf, "scsi error 0x%x", sp[0] & 0x7f); | |
1176 | msg = msgbuf; | |
1177 | goto wrapup; | |
1178 | } | |
1179 | ||
1180 | if (as->tape && (sp[2] & 0xf) == 0) { | |
1181 | if (sp[2] & 0xe0) { | |
1182 | /* either we read a file mark, the early warning EOT, | |
1183 | * or the block size did not match. In any case, the | |
1184 | * normal residue handling will work (I think) | |
1185 | */ | |
1186 | goto wrapup; | |
1187 | } | |
1188 | } | |
1189 | ||
1190 | bad = 1; | |
1191 | ||
1192 | switch (key = sp[2] & 0xf) { | |
1193 | case 1: | |
1194 | msg = "soft error"; | |
1195 | bad = 0; | |
1196 | break; | |
1197 | case 2: | |
1198 | msg = "not ready"; | |
1199 | break; | |
1200 | case 3: | |
1201 | msg = "hard error"; | |
1202 | break; | |
1203 | case 4: | |
1204 | msg = "target hardware error"; | |
1205 | break; | |
1206 | case 5: | |
1207 | msg = "illegal request"; | |
1208 | break; | |
1209 | case 6: | |
1210 | msg = "unit attention error"; | |
1211 | break; | |
1212 | case 7: | |
1213 | msg = "write protect error"; | |
1214 | break; | |
1215 | case 0xd: | |
1216 | msg = "volume overflow"; | |
1217 | break; | |
1218 | default: | |
1219 | sprintf (msgbuf, "scsi extended error 0x%x", sp[2] & 0xf); | |
1220 | msg = msgbuf; | |
1221 | break; | |
1222 | } | |
1223 | ||
1224 | wrapup: | |
1225 | ||
1226 | if (bad && msg == NULL) | |
1227 | msg = "unknown error"; | |
1228 | ||
1229 | if (msg && key != 6) { | |
1230 | diskerr (bp, "as", msg, | |
1231 | LOG_PRINTF, | |
1232 | -1, /* number of successful blks */ | |
1233 | as->have_label ? &as->label : NULL); | |
1234 | printf ("\n"); | |
1235 | } | |
1236 | ||
1237 | if (bad && key != 6) { | |
1238 | bp->b_flags |= B_ERROR; | |
1239 | printf ("scsi sense: "); | |
1240 | sp = ccb_sense (ccb); | |
1241 | for (i = 0; i < 30; i++) | |
1242 | printf ("%x ", sp[i] & 0xff); | |
1243 | printf ("\n"); | |
1244 | } | |
1245 | ||
1246 | /* this assignment mixed sizes of controller commands | |
1247 | and data to read/write. | |
1248 | bp->b_resid = (ccb->ccb_data_len_msb << 16) | |
1249 | | (ccb->ccb_data_len_mid << 8) | |
1250 | | ccb->ccb_data_len_lsb; | |
1251 | */ | |
1252 | bp->b_resid = 0; | |
1253 | ||
1254 | next: | |
1255 | asdone (as, 1); | |
1256 | } | |
1257 | ||
1258 | asdone (as, restart) | |
1259 | struct asinfo *as; | |
1260 | int restart; | |
1261 | { | |
1262 | struct buf *bp; | |
1263 | ||
1264 | bp = as->requests.b_actf; | |
1265 | as->requests.b_actf = bp->av_forw; | |
1266 | biodone (bp); | |
1267 | as->retry_count = 0; | |
1268 | if (restart && as->requests.b_actf) | |
1269 | asstart (as); | |
1270 | } | |
1271 | ||
1272 | int | |
1273 | assize (dev) | |
1274 | dev_t dev; | |
1275 | { | |
1276 | struct asinfo *as; | |
1277 | struct disklabel *lp; | |
1278 | int val; | |
1279 | ||
1280 | if (as_port == 0 || dev_target (dev) >= NTARGETS) | |
1281 | return (ENXIO); | |
1282 | ||
1283 | as = &asinfo[dev_target (dev)]; | |
1284 | ||
1285 | if (as->open == 0 | |
1286 | && asopen (dev, FREAD, S_IFBLK, NULL) != 0) | |
1287 | return (0); | |
1288 | ||
1289 | if (as->have_label == 0) | |
1290 | return (0); | |
1291 | ||
1292 | lp = &as->label; | |
1293 | val = lp->d_partitions[dev_part (dev)].p_size | |
1294 | * lp->d_secsize / DEV_BSIZE; | |
1295 | (void) asclose(dev, FREAD, S_IFBLK, NULL); | |
1296 | return (val); | |
1297 | } | |
1298 | ||
1299 | int | |
1300 | as_put_byte (val) | |
1301 | int val; | |
1302 | { | |
1303 | int i; | |
1304 | ||
1305 | for (i = 100; i > 0; i--) { | |
1306 | if ((inb (as_port + AS_STATUS) & AS_STATUS_CDF) == 0) | |
1307 | break; | |
1308 | DELAY (100); | |
1309 | } | |
1310 | if (i == 0) { | |
1311 | printf ("as: put byte timed out\n"); | |
1312 | return (-1); | |
1313 | } | |
1314 | outb (as_port + AS_DATA_OUT, val); | |
1315 | return (0); | |
1316 | } | |
1317 | ||
1318 | int | |
1319 | as_get_byte (as) | |
1320 | { | |
1321 | int i; | |
1322 | ||
1323 | for (i = 100; i > 0; i--) { | |
1324 | if ((inb (as_port + AS_STATUS) & AS_STATUS_DF) != 0) | |
1325 | break; | |
1326 | DELAY (100); | |
1327 | } | |
1328 | if (i == 0) { | |
1329 | printf ("as_get_byte timed out\n"); | |
1330 | return (-1); | |
1331 | } | |
1332 | return (inb (as_port + AS_DATA_OUT) & 0xff); | |
1333 | } | |
1334 | #endif /* NAS */ |