This commit was manufactured by cvs2svn to create tag 'FreeBSD-release/1.0'.
[unix-history] / sys / scsi / scsiconf.c
CommitLineData
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 15 * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
78ed81a3 16 *
17 * $Id: scsiconf.c,v 1.5 1993/08/28 03:08:53 rgrimes Exp $
15637ed4
RG
18 */
19
15637ed4
RG
20#include <sys/types.h>
21#include "st.h"
22#include "sd.h"
23#include "ch.h"
24#include "cd.h"
78ed81a3 25#include "sg.h"
15637ed4
RG
26
27#ifdef MACH
28#include <i386/machparam.h>
29#endif MACH
30#include <scsi/scsi_all.h>
31#include <scsi/scsiconf.h>
32
33#if !defined(OSF) && !defined(__386BSD__)
34#include "bll.h"
35#include "cals.h"
36#include "kil.h"
37#else
38#define NBLL 0
39#define NCALS 0
40#define NKIL 0
41#endif /* !defined(OSF) && !defined(__386BSD__) */
42
43#if NSD > 0
44extern sdattach();
45#endif NSD
46#if NST > 0
47extern stattach();
48#endif NST
49#if NCH > 0
50extern chattach();
51#endif NCH
52#if NCD > 0
53extern cdattach();
54#endif NCD
55#if NBLL > 0
56extern bllattach();
57#endif NBLL
58#if NCALS > 0
59extern calsattach();
60#endif NCALS
61#if NKIL > 0
62extern kil_attach();
63#endif NKIL
64
65/***************************************************************\
66* The structure of pre-configured devices that might be turned *
67* off and therefore may not show up *
68\***************************************************************/
69struct predefined
70{
71 u_char scsibus;
72 u_char dev;
73 u_char lu;
74 int (*attach_rtn)();
75 char *devname;
76 char flags;
77}
78pd[] =
79{
80#ifdef EXAMPLE_PREDEFINE
81#if NSD > 0
82 {0,0,0,sdattach,"sd",0},/* define a disk at scsibus=0 dev=0 lu=0 */
83#endif NSD
84#endif EXAMPLE_PREDEFINE
85 {0,9,9} /*illegal dummy end entry */
86};
87
88
89/***************************************************************\
90* The structure of known drivers for autoconfiguration *
91\***************************************************************/
92static struct scsidevs
93{
94 int type;
95 int removable;
96 char *manufacturer;
97 char *model;
98 char *version;
99 int (*attach_rtn)();
100 char *devname;
101 char flags; /* 1 show my comparisons during boot(debug) */
102}
103#define SC_SHOWME 0x01
104#define SC_ONE_LU 0x00
105#define SC_MORE_LUS 0x02
106knowndevs[] = {
107#if NSD > 0
108 { T_DIRECT,T_FIXED,"standard","any"
109 ,"any",sdattach,"sd",SC_ONE_LU },
110 { T_DIRECT,T_FIXED,"MAXTOR ","XT-4170S "
111 ,"B5A ",sdattach,"mx1",SC_ONE_LU },
112#endif NSD
113#if NST > 0
114 { T_SEQUENTIAL,T_REMOV,"standard","any"
115 ,"any",stattach,"st",SC_ONE_LU },
116#endif NST
117#if NCALS > 0
118 { T_PROCESSOR,T_FIXED,"standard","any"
119 ,"any",calsattach,"cals",SC_MORE_LUS },
120#endif NCALS
121#if NCH > 0
122 { T_CHANGER,T_REMOV,"standard","any"
123 ,"any",chattach,"ch",SC_ONE_LU },
124#endif NCH
125#if NCD > 0
126 { T_READONLY,T_REMOV,"SONY ","CD-ROM CDU-8012 "
127 ,"3.1a",cdattach,"cd",SC_ONE_LU },
128 { T_READONLY,T_REMOV,"PIONEER ","CD-ROM DRM-600 "
129 ,"any",cdattach,"cd",SC_MORE_LUS },
130#endif NCD
131#if NBLL > 0
132 { T_PROCESSOR,T_FIXED,"AEG ","READER "
133 ,"V1.0",bllattach,"bll",SC_MORE_LUS },
134#endif NBLL
135#if NKIL > 0
136 { T_SCANNER,T_FIXED,"KODAK ","IL Scanner 900 "
137 ,"any",kil_attach,"kil",SC_ONE_LU },
138#endif NKIL
139
140{0}
141};
142/***************************************************************\
143* Declarations *
144\***************************************************************/
145struct predefined *scsi_get_predef();
146struct scsidevs *scsi_probedev();
147struct scsidevs *selectdev();
148
149/* controls debug level within the scsi subsystem */
150/* see scsiconf.h for values */
151int scsi_debug = 0x0;
152int scsibus = 0x0; /* This is the Nth scsibus */
153
154/***************************************************************\
155* The routine called by the adapter boards to get all their *
156* devices configured in. *
157\***************************************************************/
158scsi_attachdevs( unit, scsi_addr, scsi_switch)
159int unit,scsi_addr;
160struct scsi_switch *scsi_switch;
161{
162 int targ,lun;
163 struct scsidevs *bestmatch = (struct scsidevs *)0;
164 struct predefined *predef;
165 int maybe_more;
166
167#ifdef SCSI_DELAY
168#if SCSI_DELAY > 2
78ed81a3 169 printf("%s%d waiting for scsi devices to settle\n",
170 scsi_switch->name, unit);
15637ed4 171#else SCSI_DELAY > 2
78ed81a3 172#define SCSI_DELAY 2
15637ed4
RG
173#endif SCSI_DELAY > 2
174#else
175#define SCSI_DELAY 2
176#endif SCSI_DELAY
177 spinwait(1000 * SCSI_DELAY);
178 targ = 0;
179 while(targ < 8)
180 {
181 maybe_more = 0; /* by default only check 1 lun */
182 if (targ == scsi_addr)
183 {
184 targ++;
185 continue;
186 }
187 lun = 0;
188 while(lun < 8)
189 {
190 predef = scsi_get_predef(scsibus
191 ,targ
192 ,lun
78ed81a3 193 ,scsi_switch
15637ed4
RG
194 ,&maybe_more);
195 bestmatch = scsi_probedev(unit
196 ,targ
197 ,lun
198 ,scsi_switch
199 ,&maybe_more);
200 if((bestmatch) && (predef)) /* both exist */
201 {
202 if(bestmatch->attach_rtn
203 != predef->attach_rtn)
204 {
205 printf("Clash in found/expected devices\n");
206 printf("will link in FOUND\n");
207 }
208 (*(bestmatch->attach_rtn))(unit,
209 targ,
210 lun,
211 scsi_switch);
212 }
213 if((bestmatch) && (!predef)) /* just FOUND */
214 {
215 (*(bestmatch->attach_rtn))(unit,
216 targ,
217 lun,
218 scsi_switch);
219 }
220 if((!bestmatch) && (predef)) /* just predef */
221 {
222 (*(predef->attach_rtn))(unit,
223 targ,
224 lun,
225 scsi_switch);
226 }
227 if(!(maybe_more)) /* nothing suggests we'll find more */
228 {
229 break; /* nothing here, skip to next targ */
230 }
231 /* otherwise something says we should look further*/
232 lun++;
233 }
234 targ++;
235 }
78ed81a3 236#if NSG > 0
15637ed4
RG
237 /***************************************************************\
238 * If available hook up the generic scsi driver, letting it *
239 * know which target is US. (i.e. illegal or at least special) *
240 \***************************************************************/
78ed81a3 241 sg_attach(unit,scsi_addr,scsi_switch);
15637ed4
RG
242#endif
243 scsibus++; /* next time we are on the NEXT scsi bus */
244}
245
246/***********************************************\
247* given a target and lu, check if there is a *
248* predefined device for that address *
249\***********************************************/
78ed81a3 250struct predefined *scsi_get_predef(unit,target,lu,scsi_switch,maybe_more)
15637ed4 251int unit,target,lu,*maybe_more;
78ed81a3 252struct scsi_switch *scsi_switch;
15637ed4
RG
253{
254 int upto,numents;
255
256 numents = (sizeof(pd)/sizeof(struct predefined)) - 1;
257
258 for(upto = 0;upto < numents;upto++)
259 {
260 if(pd[upto].scsibus != unit)
261 continue;
262 if(pd[upto].dev != target)
263 continue;
264 if(pd[upto].lu != lu)
265 continue;
266
78ed81a3 267 printf("%s%d targ %d lun %d: <%s> - PRECONFIGURED -\n"
268 ,scsi_switch->name
269 ,unit
15637ed4
RG
270 ,target
271 ,lu
272 ,pd[upto].devname);
273 *maybe_more = pd[upto].flags & SC_MORE_LUS;
274 return(&(pd[upto]));
275 }
276 return((struct predefined *)0);
277}
278
279/***********************************************\
280* given a target and lu, ask the device what *
281* it is, and find the correct driver table *
282* entry. *
283\***********************************************/
284struct scsidevs *scsi_probedev(unit,target,lu,scsi_switch, maybe_more)
285
286struct scsi_switch *scsi_switch;
287int unit,target,lu;
288int *maybe_more;
289{
290 struct scsidevs *bestmatch = (struct scsidevs *)0;
291 char *dtype=(char *)0,*desc;
292 char *qtype;
293 static struct scsi_inquiry_data inqbuf;
294 int len,qualifier,type,remov;
295 char manu[32];
296 char model[32];
297 char version[32];
298
299
300 bzero(&inqbuf,sizeof(inqbuf));
301 /***********************************************\
302 * Ask the device what it is *
303 \***********************************************/
304#ifdef DEBUG
305 if((target == 0) && (lu == 0))
306 scsi_debug = 0xfff;
307 else
308 scsi_debug = 0;
309#endif DEBUG
310 if(scsi_ready( unit,
311 target,
312 lu,
313 scsi_switch,
314 SCSI_NOSLEEP | SCSI_NOMASK) != COMPLETE)
315 {
316 return(struct scsidevs *)0;
317 }
318 if(scsi_inquire(unit,
319 target,
320 lu,
321 scsi_switch,
322 &inqbuf,
323 SCSI_NOSLEEP | SCSI_NOMASK) != COMPLETE)
324 {
325 return(struct scsidevs *)0;
326 }
327
328 /***********************************************\
329 * note what BASIC type of device it is *
330 \***********************************************/
331 if(scsi_debug & SHOWINQUIRY)
332 {
333 desc=(char *)&inqbuf;
334 printf("inq: %x %x %x %x %x %x %x %x %x %x %x %x %x\n",
335 desc[0], desc[1], desc[2], desc[3],
336 desc[4], desc[5], desc[6], desc[7],
337 desc[8], desc[9], desc[10], desc[11],
338 desc[12]);
339 }
340
78ed81a3 341 type = inqbuf.device & SID_TYPE;
342 qualifier = inqbuf.device & SID_QUAL;
343 remov = inqbuf.dev_qual2 & SID_REMOVABLE;
15637ed4 344
15637ed4
RG
345
346 /* Any device qualifier that has
347 * the top bit set (qualifier&4 != 0) is vendor specific and
348 * won't match in this switch.
349 */
350
351 switch(qualifier)
352 {
78ed81a3 353 case SID_QUAL_LU_OK:
15637ed4
RG
354 qtype="";
355 break;
78ed81a3 356
357 case SID_QUAL_LU_OFFLINE:
15637ed4
RG
358 qtype=", Unit not Connected!";
359 break;
78ed81a3 360
361 case SID_QUAL_RSVD:
15637ed4 362 qtype=", Reserved Peripheral Qualifier!";
78ed81a3 363 *maybe_more = 1;
364 return (struct scsidevs *)0;
15637ed4 365 break;
78ed81a3 366
367 case SID_QUAL_BAD_LU:
368 /*
369 * Check for a non-existent unit. If the device is returning
370 * this much, then we must set the flag that has
371 * the searcher keep looking on other luns.
372 */
15637ed4 373 qtype=", The Target can't support this Unit!";
78ed81a3 374 *maybe_more = 1;
375 return (struct scsidevs *)0;
15637ed4 376
78ed81a3 377 default:
15637ed4
RG
378 dtype="vendor specific";
379 qtype="";
380 *maybe_more = 1;
381 break;
382 }
383
384 if (dtype == 0)
78ed81a3 385 {
15637ed4
RG
386 switch(type)
387 {
78ed81a3 388 case T_DIRECT:
389 dtype="direct";
390 break;
391 case T_SEQUENTIAL:
392 dtype="sequential";
393 break;
394 case T_PRINTER:
395 dtype="printer";
396 break;
397 case T_PROCESSOR:
398 dtype="processor";
399 break;
400 case T_READONLY:
401 dtype="readonly";
402 break;
403 case T_WORM:
404 dtype="worm";
405 break;
406 case T_SCANNER:
407 dtype="scanner";
408 break;
409 case T_OPTICAL:
410 dtype="optical";
411 break;
412 case T_CHANGER:
413 dtype="changer";
414 break;
415 case T_COMM:
416 dtype="communication";
417 break;
418 case T_NODEVICE:
419 *maybe_more = 1;
420 return (struct scsidevs *)0;
421 default:
422 dtype="unknown";
423 break;
15637ed4
RG
424 }
425
78ed81a3 426 }
15637ed4
RG
427 /***********************************************\
428 * Then if it's advanced enough, more detailed *
429 * information *
430 \***********************************************/
78ed81a3 431 if((inqbuf.version & SID_ANSII) > 0)
15637ed4
RG
432 {
433 if ((len = inqbuf.additional_length
434 + ( (char *)inqbuf.unused
435 - (char *)&inqbuf))
436 > (sizeof(struct scsi_inquiry_data) - 1))
437 len = sizeof(struct scsi_inquiry_data) - 1;
438 desc=inqbuf.vendor;
439 desc[len-(desc - (char *)&inqbuf)] = 0;
440 strncpy(manu,inqbuf.vendor,8);manu[8]=0;
441 strncpy(model,inqbuf.product,16);model[16]=0;
442 strncpy(version,inqbuf.revision,4);version[4]=0;
443 }
444 else
445 /***********************************************\
446 * If not advanced enough, use default values *
447 \***********************************************/
448 {
449 desc="early protocol device";
450 strncpy(manu,"unknown",8);
451 strncpy(model,"unknown",16);
452 strncpy(version,"????",4);
453 }
78ed81a3 454 printf("%s%d targ %d lun %d: type %d(%s) %s SCSI%d\n"
455 ,scsi_switch->name
456 ,unit
15637ed4
RG
457 ,target
458 ,lu
78ed81a3 459 ,type
460 ,dtype
15637ed4 461 ,remov?"removable":"fixed"
78ed81a3 462 ,inqbuf.version & SID_ANSII
463 );
464 printf("%s%d targ %d lun %d: <%s%s%s>\n"
465 ,scsi_switch->name
466 ,unit
467 ,target
468 ,lu
15637ed4
RG
469 ,manu
470 ,model
471 ,version
15637ed4 472 );
78ed81a3 473 if(qtype[0])
474 {
475 printf("%s%d targ %d lun %d: qualifier %d(%s)\n"
476 ,scsi_switch->name
477 ,unit
478 ,target
479 ,lu
480 ,qualifier
481 ,qtype
482 );
483 }
15637ed4
RG
484 /***********************************************\
485 * Try make as good a match as possible with *
486 * available sub drivers *
487 \***********************************************/
488 bestmatch = (selectdev(unit,target,lu,&scsi_switch,
78ed81a3 489 qualifier,type,remov?T_REMOV:T_FIXED,manu,model,version));
15637ed4
RG
490 if((bestmatch) && (bestmatch->flags & SC_MORE_LUS))
491 {
492 *maybe_more = 1;
493 }
494 return(bestmatch);
495}
496
497/***********************************************\
498* Try make as good a match as possible with *
499* available sub drivers *
500\***********************************************/
501struct scsidevs
502*selectdev(unit,target,lu,dvr_switch,qualifier,type,remov,manu,model,rev)
503int unit,target,lu;
504struct scsi_switch *dvr_switch;
505int qualifier,type,remov;
506char *manu,*model,*rev;
507{
508 int numents = (sizeof(knowndevs)/sizeof(struct scsidevs)) - 1;
509 int count = 0;
510 int bestmatches = 0;
511 struct scsidevs *bestmatch = (struct scsidevs *)0;
512 struct scsidevs *thisentry = knowndevs;
513
78ed81a3 514 type |= qualifier; /* why? */
15637ed4
RG
515
516 thisentry--;
517 while( count++ < numents)
518 {
519 thisentry++;
520 if(type != thisentry->type)
521 {
522 continue;
523 }
524 if(bestmatches < 1)
525 {
526 bestmatches = 1;
527 bestmatch = thisentry;
528 }
529 if(remov != thisentry->removable)
530 {
531 continue;
532 }
533 if(bestmatches < 2)
534 {
535 bestmatches = 2;
536 bestmatch = thisentry;
537 }
538 if(thisentry->flags & SC_SHOWME)
539 printf("\n%s-\n%s-",thisentry->manufacturer, manu);
540 if(strcmp(thisentry->manufacturer, manu))
541 {
542 continue;
543 }
544 if(bestmatches < 3)
545 {
546 bestmatches = 3;
547 bestmatch = thisentry;
548 }
549 if(thisentry->flags & SC_SHOWME)
550 printf("\n%s-\n%s-",thisentry->model, model);
551 if(strcmp(thisentry->model, model))
552 {
553 continue;
554 }
555 if(bestmatches < 4)
556 {
557 bestmatches = 4;
558 bestmatch = thisentry;
559 }
560 if(thisentry->flags & SC_SHOWME)
561 printf("\n%s-\n%s-",thisentry->version, rev);
562 if(strcmp(thisentry->version, rev))
563 {
564 continue;
565 }
566 if(bestmatches < 5)
567 {
568 bestmatches = 5;
569 bestmatch = thisentry;
570 break;
571 }
572 }
573
574 if (bestmatch == (struct scsidevs *)0)
575 printf(" No explicit device driver match for \"%s %s\".\n",
576 manu, model);
577
578 return(bestmatch);
579}
580
581static int recurse = 0;
582/***********************************************\
583* Do a scsi operation asking a device if it is *
584* ready. Use the scsi_cmd routine in the switch *
585* table. *
586\***********************************************/
587scsi_ready(unit,target,lu,scsi_switch, flags)
588struct scsi_switch *scsi_switch;
589{
590 struct scsi_test_unit_ready scsi_cmd;
591 struct scsi_xfer scsi_xfer;
592 volatile int rval;
593 int key;
594
595 bzero(&scsi_cmd, sizeof(scsi_cmd));
596 bzero(&scsi_xfer, sizeof(scsi_xfer));
597 scsi_cmd.op_code = TEST_UNIT_READY;
598
599 scsi_xfer.flags=flags | INUSE;
600 scsi_xfer.adapter=unit;
601 scsi_xfer.targ=target;
602 scsi_xfer.lu=lu;
603 scsi_xfer.cmd=(struct scsi_generic *)&scsi_cmd;
604 scsi_xfer.retries=8;
605 scsi_xfer.timeout=10000;
606 scsi_xfer.cmdlen=sizeof(scsi_cmd);
607 scsi_xfer.data=0;
608 scsi_xfer.datalen=0;
609 scsi_xfer.resid=0;
610 scsi_xfer.when_done=0;
611 scsi_xfer.done_arg=0;
612retry: scsi_xfer.error=0;
613 /*******************************************************\
614 * do not use interrupts *
615 \*******************************************************/
616 rval = (*(scsi_switch->scsi_cmd))(&scsi_xfer);
617 if (rval != COMPLETE)
618 {
619 if(scsi_debug)
620 {
621 printf("scsi error, rval = 0x%x\n",rval);
622 printf("code from driver: 0x%x\n",scsi_xfer.error);
623 }
624 switch(scsi_xfer.error)
625 {
626 case XS_SENSE:
627 /*******************************************************\
628 * Any sense value is illegal except UNIT ATTENTION *
629 * In which case we need to check again to get the *
630 * correct response. *
631 *( especially exabytes) *
632 \*******************************************************/
78ed81a3 633 if(((scsi_xfer.sense.error_code & SSD_ERRCODE) == 0x70 )
634 ||((scsi_xfer.sense.error_code & SSD_ERRCODE) == 0x71 ))
15637ed4 635 {
78ed81a3 636 key = scsi_xfer.sense.ext.extended.flags & SSD_KEY ;
15637ed4
RG
637 switch(key)
638 {
639 case 2: /* not ready BUT PRESENT! */
640 return(COMPLETE);
641 case 6:
642 spinwait(1000);
643 if(scsi_xfer.retries--)
644 {
645 scsi_xfer.flags &= ~ITSDONE;
646 goto retry;
647 }
648 return(COMPLETE);
649 default:
650 if(scsi_debug)
651 printf("%d:%d,key=%x.",
652 target,lu,key);
653 }
654 }
655 return(HAD_ERROR);
656 case XS_BUSY:
657 spinwait(1000);
658 if(scsi_xfer.retries--)
659 {
660 scsi_xfer.flags &= ~ITSDONE;
661 goto retry;
662 }
663 return(COMPLETE); /* it's busy so it's there */
664 case XS_TIMEOUT:
665 default:
666 return(HAD_ERROR);
667 }
668 }
669 return(COMPLETE);
670}
671/***********************************************\
672* Do a scsi operation asking a device what it is*
673* Use the scsi_cmd routine in the switch table. *
674\***********************************************/
675scsi_inquire(unit,target,lu,scsi_switch,inqbuf, flags)
676struct scsi_switch *scsi_switch;
677u_char *inqbuf;
678{
679 struct scsi_inquiry scsi_cmd;
680 struct scsi_xfer scsi_xfer;
681 volatile int rval;
682
683 bzero(&scsi_cmd, sizeof(scsi_cmd));
684 bzero(&scsi_xfer, sizeof(scsi_xfer));
685 scsi_cmd.op_code = INQUIRY;
686 scsi_cmd.length = sizeof(struct scsi_inquiry_data);
687
688 scsi_xfer.flags=flags | SCSI_DATA_IN | INUSE;
689 scsi_xfer.adapter=unit;
690 scsi_xfer.targ=target;
691 scsi_xfer.lu=lu;
692 scsi_xfer.retries=8;
693 scsi_xfer.timeout=10000;
694 scsi_xfer.cmd=(struct scsi_generic *)&scsi_cmd;
695 scsi_xfer.cmdlen= sizeof(struct scsi_inquiry);
696 scsi_xfer.data=inqbuf;
697 scsi_xfer.datalen=sizeof(struct scsi_inquiry_data);
698 scsi_xfer.resid=sizeof(struct scsi_inquiry_data);
699 scsi_xfer.when_done=0;
700 scsi_xfer.done_arg=0;
701retry: scsi_xfer.error=0;
702 /*******************************************************\
703 * do not use interrupts *
704 \*******************************************************/
705 if ((*(scsi_switch->scsi_cmd))(&scsi_xfer) != COMPLETE)
706 {
707 if(scsi_debug) printf("inquiry had error(0x%x) ",scsi_xfer.error);
708 switch(scsi_xfer.error)
709 {
710 case XS_NOERROR:
711 break;
712 case XS_SENSE:
713 /*******************************************************\
714 * Any sense value is illegal except UNIT ATTENTION *
715 * In which case we need to check again to get the *
716 * correct response. *
717 *( especially exabytes) *
718 \*******************************************************/
78ed81a3 719 if(((scsi_xfer.sense.error_code & SSD_ERRCODE) == 0x70 )
720 && ((scsi_xfer.sense.ext.extended.flags & SSD_KEY) == 6))
15637ed4
RG
721 { /* it's changed so it's there */
722 spinwait(1000);
723 {
724 if(scsi_xfer.retries--)
725 {
726 scsi_xfer.flags &= ~ITSDONE;
727 goto retry;
728 }
729 }
730 return( COMPLETE);
731 }
732 return(HAD_ERROR);
733 case XS_BUSY:
734 spinwait(1000);
735 if(scsi_xfer.retries--)
736 {
737 scsi_xfer.flags &= ~ITSDONE;
738 goto retry;
739 }
740 case XS_TIMEOUT:
741 default:
742 return(HAD_ERROR);
743 }
744 }
745 return(COMPLETE);
746}
747
748
749
750
751/***********************************************\
752* Utility routines often used in SCSI stuff *
753\***********************************************/
754
755/***********************************************\
756* convert a physical address to 3 bytes, *
757* MSB at the lowest address, *
758* LSB at the highest. *
759\***********************************************/
760
761lto3b(val, bytes)
762u_char *bytes;
763{
764 *bytes++ = (val&0xff0000)>>16;
765 *bytes++ = (val&0xff00)>>8;
766 *bytes = val&0xff;
767}
768
769/***********************************************\
770* The reverse of lto3b *
771\***********************************************/
772_3btol(bytes)
773u_char *bytes;
774{
775 int rc;
776 rc = (*bytes++ << 16);
777 rc += (*bytes++ << 8);
778 rc += *bytes;
779 return(rc);
780}
781