source: trunk/third/sysinfo/myscsi.c @ 12269

Revision 12269, 15.6 KB checked in by ghudson, 26 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r12268, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * Copyright (c) 1992-1998 Michael A. Cooper.
3 * This software may be freely used and distributed provided it is not
4 * sold for profit or used in part or in whole for commercial gain
5 * without prior written agreement, and the author is credited
6 * appropriately.
7 */
8
9#ifndef lint
10static char *RCSid = "$Revision: 1.1.1.1 $";
11#endif
12
13/*
14 * Common SysInfo SCSI functions
15 */
16
17#include "defs.h"
18#include "myscsi.h"
19#include <netinet/in.h>         /* For ntohs() etc. */
20
21/*
22 * Do setup for Scsi*Decode() funcs which need a DiskDrive_t to work on
23 */
24static DiskDrive_t *DiskSetup(DevInfo, What)
25     DevInfo_t                 *DevInfo;
26     char                      *What;
27{
28    DiskDriveData_t            *DiskDriveData;
29
30    if (!DevInfo || !What)
31        return((DiskDrive_t *) NULL);
32
33    /*
34     * We may want to add other DevType's as we discover them, but
35     * right now we only know how to deal with DiskDrive's.
36     */
37    if (DevInfo->Type != DT_DISKDRIVE) {
38        SImsg(SIM_DBG, "%s: %s unsupported for DevType %d",
39              DevInfo->Name, What, DevInfo->Type);
40        return((DiskDrive_t *) NULL);
41    }
42
43    /*
44     * Find or create the DiskDriveData and DiskDrive we need
45     */
46    if (DevInfo->DevSpec)
47        DiskDriveData = (DiskDriveData_t *) DevInfo->DevSpec;
48    else {
49        DiskDriveData = NewDiskDriveData(NULL);
50        DevInfo->DevSpec = (void *) DiskDriveData;
51    }
52    if (!DiskDriveData->HWdata)
53        DiskDriveData->HWdata = NewDiskDrive(NULL);
54
55    return(DiskDriveData->HWdata);
56}
57
58/*
59 * Decode a SCSI CAPACITY command and add info to DevInfo as we can.
60 */
61extern int ScsiCapacityDecode(Query)
62    ScsiQuery_t                *Query;
63{
64    ScsiCapacity_t             *Capacity;
65    DiskDrive_t                *Disk;
66    DevInfo_t                  *DevInfo;
67
68    if (!Query|| !Query->DevInfo || !Query->Data)
69        return(-1);
70
71    Capacity = (ScsiCapacity_t *) Query->Data;
72    DevInfo = Query->DevInfo;
73
74    SImsg(SIM_DBG,
75          "\t%s: SCSI CAPACITY: Blocks=<%d> BlockSize=<%d>",
76          DevInfo->Name, ntohl(Capacity->Blocks), ntohl(Capacity->BlkSize));
77
78    if (!(Disk = DiskSetup(DevInfo, "ScsiCapacityDecode")))
79        return(-1);
80
81    /*
82     * Set what we know
83     */
84    Disk->Size = nsect_to_mbytes( ntohl(Capacity->Blocks),
85                                  ntohl(Capacity->BlkSize) );
86    Disk->SecSize = ntohl(Capacity->BlkSize);
87
88    return(0);
89}
90
91/*
92 * Decode a SCSI INQUIRY command and add info to DevInfo as we can.
93 */
94extern int ScsiInquiryDecode(Query)
95    ScsiQuery_t                *Query;
96{
97    ScsiInquiry_t              *Inq;
98    DevInfo_t                  *DevInfo;
99    Define_t                   *Def;
100    char                       *DevType = NULL;
101    char                       *cp;
102
103    if (!Query || !Query->Data || !Query->DevInfo) {
104        SImsg(SIM_DBG, "ScsiInquiryDecode: Bad parameters");
105        return(-1);
106    }
107
108    Inq = (ScsiInquiry_t *) Query->Data;
109    DevInfo = Query->DevInfo;
110
111    SImsg(SIM_DBG,
112          "\t%s: SCSI INQUIRY: vendor=<%.*s> product=<%.*s>",
113          DevInfo->Name,
114          sizeof(Inq->inq_vid), Inq->inq_vid,
115          sizeof(Inq->inq_pid), Inq->inq_pid);
116    SImsg(SIM_DBG,
117          "\t%s: SCSI INQUIRY:    rev=<%.*s> serial=<%.*s>",
118          DevInfo->Name,
119          sizeof(Inq->inq_revision), Inq->inq_revision,
120          sizeof(Inq->inq_serial), Inq->inq_serial);
121
122    /*
123     * This is implied by this function being called
124     */
125    DevInfo->ClassType = CT_SCSI;
126
127    /*
128     * Decode results
129     */
130#define IsOk(s) ( s && s[0] && s[0] != ' ' && isalnum(s[0]) )
131    if (IsOk(Inq->inq_vid))
132        DevInfo->Vendor = CleanString(Inq->inq_vid, sizeof(Inq->inq_vid), 0);
133    if (IsOk(Inq->inq_pid))
134        DevInfo->Model = CleanString(Inq->inq_pid, sizeof(Inq->inq_pid), 0);
135    if (IsOk(Inq->inq_revision))
136        DevInfo->Revision = CleanString(Inq->inq_revision,
137                                        sizeof(Inq->inq_revision), 0);
138    if (IsOk(Inq->inq_serial))
139        DevInfo->Serial = CleanString(Inq->inq_serial,
140                                      sizeof(Inq->inq_serial), 0);
141#undef IsOk
142    /*
143     * What SCSI version are we?
144     */
145    cp = NULL;
146    switch ((int)Inq->inq_rdf) {
147    case RDF_LEVEL0:    cp = "SCSI-1";  break;
148    case RDF_SCSI2:     cp = "SCSI-2";  break;
149    case RDF_CCS:       cp = "CCS";     break;
150    }
151    if (cp)
152        AddDevDesc(DevInfo, cp, "SCSI Version/Protocol", DA_APPEND);
153    else
154        SImsg(SIM_UNKN, "Unknown RDF/SCSI Version 0x%x",
155              Inq->inq_rdf);
156
157    /*
158     * ANSI/ECMA/ISO version info
159     */
160    AddDevDesc(DevInfo, itoa(Inq->inq_ansi), "ANSI Version", DA_APPEND);
161    AddDevDesc(DevInfo, itoa(Inq->inq_ecma), "ECMA Version", DA_APPEND);
162    AddDevDesc(DevInfo, itoa(Inq->inq_iso), "ISO Version", DA_APPEND);
163
164    /*
165     * Check all the flag bits
166     */
167    if (Inq->inq_rmb)
168        AddDevDesc(DevInfo, "Removable Media", "Has", DA_APPEND);
169    if (Inq->inq_normaca)
170        AddDevDesc(DevInfo, "Setting NACA bit", "Has", DA_APPEND);
171    if (Inq->inq_trmiop)
172        AddDevDesc(DevInfo, "TERMINATE I/O PROC msg", "Has", DA_APPEND);
173    if (Inq->inq_aenc)
174        AddDevDesc(DevInfo, "Async Event Notification", "Has", DA_APPEND);
175    if (Inq->inq_wbus16)
176        AddDevDesc(DevInfo, "Wide SCSI: 16-bit Data Transfers",
177                   "Has", DA_APPEND);
178    if (Inq->inq_wbus32)
179        AddDevDesc(DevInfo, "Wide SCSI: 32-bit Data Transfers",
180                   "Has", DA_APPEND);
181    if (Inq->inq_addr16)
182        AddDevDesc(DevInfo, "Wide SCSI: 16-bit Addressing",
183                   "Has", DA_APPEND);
184    if (Inq->inq_addr32)
185        AddDevDesc(DevInfo, "Wide SCSI: 32-bit Addressing",
186                   "Has", DA_APPEND);
187    if (Inq->inq_ackqreqq)
188        AddDevDesc(DevInfo, "Data Transfer on Q Cable", "Has", DA_APPEND);
189    if (Inq->inq_mchngr)
190        AddDevDesc(DevInfo, "Embedded/attached to medium changer",
191                   "Has", DA_APPEND);
192    if (Inq->inq_dualp)
193        AddDevDesc(DevInfo, "Dual Port Device", "Has", DA_APPEND);
194    if (Inq->inq_trandis)
195        AddDevDesc(DevInfo, "Transfer Disable Messages", "Has", DA_APPEND);
196    if (Inq->inq_sftre)
197        AddDevDesc(DevInfo, "Soft Reset option", "Has", DA_APPEND);
198    if (Inq->inq_cmdque)
199        AddDevDesc(DevInfo, "Command Queuing", "Has", DA_APPEND);
200    if (Inq->inq_linked)
201        AddDevDesc(DevInfo, "Linked Commands", "Has", DA_APPEND);
202    if (Inq->inq_sync)
203        AddDevDesc(DevInfo, "Syncronous Data Transfers", "Has", DA_APPEND);
204    if (Inq->inq_reladdr)
205        AddDevDesc(DevInfo, "Relative Addressing", "Has", DA_APPEND);
206
207    /*
208     * Look up device type
209     */
210    Def = DefGet(DL_SCSI_DTYPE, (char *) NULL, (long) Inq->inq_dtype, 0);
211    if (Def) {
212        /*
213         * Set Device Type
214         */
215        if (Def->ValStr1) {
216            DevType_t           *dtPtr;
217
218            dtPtr = TypeGetByName(Def->ValStr1);
219            if (dtPtr)
220                DevInfo->Type = dtPtr->Type;
221            else
222                SImsg(SIM_DBG, "%s: SCSIdtype DevType=<%s> is unknown.",
223                      DevInfo->Name, Def->ValStr1);
224        }
225    } else
226        SImsg(SIM_DBG, "%s: Unknown SCSIdtype=0x%02x",
227              DevInfo->Name, Inq->inq_dtype);
228
229    return(0);
230}
231     
232/*
233 * Get description info about SCSI devices by sending a SCSI INQUIRY
234 * to the device.
235 */
236extern int ScsiQueryInquiry(Query)
237     ScsiQuery_t               *Query;
238{
239    static ScsiCdbG0_t          Cdb;
240    static ScsiCmd_t            Cmd;
241
242    if (!Query) {
243        SImsg(SIM_DBG, "ScsiInquiry: Bad parameters");
244        return(-1);
245    }
246
247    /*
248     * Initialize
249     */
250    memset(&Cdb, 0, sizeof(Cdb));
251    Cdb.cmd = CMD_INQUIRY;
252    Cdb.length = sizeof(ScsiInquiry_t);
253
254    memset(&Cmd, 0, sizeof(Cmd));
255    Cmd.Cdb = &Cdb;
256    Cmd.CdbLen = sizeof(Cdb);
257    Cmd.DevFD = Query->DevFD;
258    Cmd.DevFile = Query->DevFile;
259
260    if (ScsiCmd(&Cmd) == 0) {
261        /*
262         * Decode results
263         */
264        Query->Data = Cmd.Data;
265        return ScsiInquiryDecode(Query);
266    } else
267        return(-1);
268}
269
270/*
271 * Get description info about SCSI devices by sending a SCSI CAPACITY
272 * to the device.
273 */
274extern int ScsiQueryCapacity(Query)
275     ScsiQuery_t               *Query; 
276{
277    static ScsiCdbG1_t          Cdb;
278    static ScsiCmd_t            Cmd;
279
280    if (!Query) {
281        SImsg(SIM_DBG, "ScsiCapacity: Bad parameters");
282        return(-1);
283    }
284
285    /*
286     * Initialize
287     */
288    memset(&Cdb, 0, sizeof(Cdb));
289    Cdb.cmd = CMD_CAPACITY;
290
291    memset(&Cmd, 0, sizeof(Cmd));
292    Cmd.Cdb = &Cdb;
293    Cmd.CdbLen = sizeof(Cdb);
294    Cmd.DevFD = Query->DevFD;
295    Cmd.DevFile = Query->DevFile;
296
297    if (ScsiCmd(&Cmd) == 0) {
298        /*
299         * Decode results
300         */
301        Query->Data = Cmd.Data;
302        return ScsiCapacityDecode(Query);
303    } else
304        return(-1);
305}
306
307/*
308 * Decode a SCSI GEOMETRY command and add info to DevInfo as we can.
309 */
310extern int ScsiGeometryDecode(Query)
311    ScsiQuery_t                *Query;
312{
313    ScsiModeGeometry_t         *Geometry;
314    DiskDrive_t                *Disk;
315    DevInfo_t                  *DevInfo;
316
317    if (!Query|| !Query->DevInfo || !Query->Data)
318        return(-1);
319
320    Geometry = (ScsiModeGeometry_t *) Query->Data;
321    DevInfo = Query->DevInfo;
322
323    SImsg(SIM_DBG,
324          "\t%s: SCSI GEOMETRY: #tracks=<%d>",
325          DevInfo->Name, Geometry->heads);
326
327    if (!(Disk = DiskSetup(DevInfo, "ScsiGeometryDecode")))
328        return(-1);
329
330    Disk->Tracks = Geometry->heads;
331    Disk->PhyCyl = (int)(Geometry->cyl_ub << 16) + (int)(Geometry->cyl_mb << 8)
332        + (int)(Geometry->cyl_lb);
333    Disk->RPM = ntohs(Geometry->rpm);
334
335    return(0);
336}
337
338/*
339 * Decode a SCSI FORMAT command and add info to DevInfo as we can.
340 */
341extern int ScsiFormatDecode(Query)
342    ScsiQuery_t                *Query;
343{
344    ScsiModeFormat_t           *Format;
345    DiskDrive_t                *Disk;
346    DevInfo_t                  *DevInfo;
347
348    if (!Query|| !Query->DevInfo || !Query->Data)
349        return(-1);
350
351    Format = (ScsiModeFormat_t *) Query->Data;
352    DevInfo = Query->DevInfo;
353
354    SImsg(SIM_DBG,
355          "\t%s: SCSI FORMAT: #sect=<%d> secsize=<%d>",
356          DevInfo->Name, ntohs(Format->sect_track),
357          ntohs(Format->data_bytes_sect));
358
359    if (!(Disk = DiskSetup(DevInfo, "ScsiFormatDecode")))
360        return(-1);
361
362    Disk->Sect = ntohs(Format->sect_track);
363    Disk->SecSize = ntohs(Format->data_bytes_sect);
364    Disk->Tracks = ntohs(Format->tracks_per_zone);
365    Disk->AltSectPerZone = ntohs(Format->alt_sect_zone);
366    Disk->AltTracksPerVol = ntohs(Format->alt_tracks_vol);
367    Disk->AltTracksPerZone = ntohs(Format->alt_tracks_zone);
368    Disk->IntrLv = ntohs(Format->interleave);
369    Disk->TrackSkew = ntohs(Format->track_skew);
370    Disk->CylSkew = ntohs(Format->cylinder_skew);
371
372    return(0);
373}
374
375/*
376 * Get description info about SCSI devices by sending a SCSI FORMAT
377 * to the device.
378 */
379extern int ScsiQueryFormat(Query)
380     ScsiQuery_t               *Query; 
381{
382    static ScsiCdbG0_t          Cdb;
383    static ScsiCmd_t            Cmd;
384    static ScsiModeFormat_t     Format;
385    ScsiModeHeader_t           *Hdr;
386    char                       *LocPtr;
387
388    if (!Query) {
389        SImsg(SIM_DBG, "ScsiFormat: Bad parameters");
390        return(-1);
391    }
392
393    /*
394     * Initialize
395     */
396    memset(&Cdb, 0, sizeof(Cdb));
397    Cdb.cmd = CMD_MODE_SENSE;
398    Cdb.addr1 = DAD_MODE_FORMAT;
399    Cdb.length = 255;   /* Yuck.  It's hardcoded */
400
401    memset(&Cmd, 0, sizeof(Cmd));
402    Cmd.Cdb = &Cdb;
403    Cmd.CdbLen = sizeof(Cdb);
404    Cmd.DevFD = Query->DevFD;
405    Cmd.DevFile = Query->DevFile;
406
407    if (ScsiCmd(&Cmd) == 0) {
408        /*
409         * Decode results
410         */
411        Hdr = (ScsiModeHeader_t *) Cmd.Data;
412        LocPtr = SCSI_MODE_PAGE_ADDR(Hdr, char);
413        (void) memset(&Format, 0, sizeof(Format));
414        (void) memcpy(&Format, LocPtr, sizeof(ScsiModePage_t));
415        (void) memcpy(&Format, LocPtr, Format.mode_page.length);
416        Query->Data = (void *) &Format;
417        return ScsiFormatDecode(Query);
418    } else
419        return(-1);
420}
421
422/*
423 * Get description info about SCSI devices by sending a SCSI GEOMETRY
424 * to the device.
425 */
426extern int ScsiQueryGeometry(Query)
427     ScsiQuery_t               *Query; 
428{
429    static ScsiCdbG0_t          Cdb;
430    static ScsiCmd_t            Cmd;
431    static ScsiModeGeometry_t   Geometry;
432    ScsiModeHeader_t           *Hdr;
433    char                       *LocPtr;
434
435    if (!Query) {
436        SImsg(SIM_DBG, "ScsiGeometry: Bad parameters");
437        return(-1);
438    }
439
440    /*
441     * Initialize
442     */
443    memset(&Cdb, 0, sizeof(Cdb));
444    Cdb.cmd = CMD_MODE_SENSE;
445    Cdb.addr1 = DAD_MODE_GEOMETRY;
446    Cdb.length = 255;   /* Yuck.  It's hardcoded */
447
448    memset(&Cmd, 0, sizeof(Cmd));
449    Cmd.Cdb = &Cdb;
450    Cmd.CdbLen = sizeof(Cdb);
451    Cmd.DevFD = Query->DevFD;
452    Cmd.DevFile = Query->DevFile;
453
454    if (ScsiCmd(&Cmd) == 0) {
455        /*
456         * Decode results
457         */
458        Hdr = (ScsiModeHeader_t *) Cmd.Data;
459        LocPtr = SCSI_MODE_PAGE_ADDR(Hdr, char);
460        (void) memset(&Geometry, 0, sizeof(Geometry));
461        (void) memcpy(&Geometry, LocPtr, sizeof(ScsiModePage_t));
462        (void) memcpy(&Geometry, LocPtr, Geometry.mode_page.length);
463        Query->Data = (void *) &Geometry;
464        return ScsiGeometryDecode(Query);
465    } else
466        return(-1);
467}
468
469/*
470 * Decode a SCSI SPEED command and add info to DevInfo as we can.
471 */
472extern int ScsiSpeedDecode(Query)
473    ScsiQuery_t                *Query;
474{
475    ScsiModeSpeed_t            *Speed;
476    DevInfo_t                  *DevInfo;
477
478    if (!Query|| !Query->DevInfo || !Query->Data)
479        return(-1);
480
481    Speed = (ScsiModeSpeed_t *) Query->Data;
482    DevInfo = Query->DevInfo;
483
484    SImsg(SIM_DBG,
485          "\t%s: SCSI SPEED: speed=<%d>",
486          DevInfo->Name, ntohs(Speed->speed));
487
488    /*
489     * XXX Don't know how useful this will be or what the "speed" values
490     * will be, so for now, we just print a debug.
491     */
492
493    return(0);
494}
495
496/*
497 * Get the speed of a SCSI device.
498 * This only works on CD-ROM's right now.
499 */
500extern int ScsiQuerySpeed(Query)
501     ScsiQuery_t               *Query; 
502{
503    static ScsiCdbG0_t          Cdb;
504    static ScsiCmd_t            Cmd;
505    static ScsiModeSpeed_t      Speed;
506    ScsiModeHeader_t           *Hdr;
507    char                       *LocPtr;
508
509    if (!Query) {
510        SImsg(SIM_DBG, "ScsiSpeed: Bad parameters");
511        return(-1);
512    }
513
514    if (Query->DevInfo && Query->DevInfo->Type != DT_CDROM) {
515        SImsg(SIM_DBG, "%s: Not a CDROM (%d).  Skipping ScsiQuerySpeed.",
516              Query->DevInfo->Name, Query->DevInfo->Type);
517        return(-1);
518    }
519
520    /*
521     * Initialize
522     */
523    memset(&Cdb, 0, sizeof(Cdb));
524    Cdb.cmd = CMD_MODE_SENSE;
525    Cdb.addr1 = CDROM_MODE_SPEED;
526    Cdb.length = 255;   /* Yuck.  It's hardcoded */
527
528    memset(&Cmd, 0, sizeof(Cmd));
529    Cmd.Cdb = &Cdb;
530    Cmd.CdbLen = sizeof(Cdb);
531    Cmd.DevFD = Query->DevFD;
532    Cmd.DevFile = Query->DevFile;
533
534    if (ScsiCmd(&Cmd) == 0) {
535        /*
536         * Decode results
537         */
538        Hdr = (ScsiModeHeader_t *) Cmd.Data;
539        LocPtr = SCSI_MODE_PAGE_ADDR(Hdr, char);
540        (void) memset(&Speed, 0, sizeof(Speed));
541        (void) memcpy(&Speed, LocPtr, sizeof(ScsiModePage_t));
542        (void) memcpy(&Speed, LocPtr, Speed.mode_page.length);
543        Query->Data = (void *) &Speed;
544        return ScsiSpeedDecode(Query);
545    } else
546        return(-1);
547}
548
549/*
550 * Query a device for SCSI information.
551 */
552extern int ScsiQuery(DevInfo, DevFile, DevFD, OverRide)
553    DevInfo_t                  *DevInfo;
554    char                       *DevFile;
555    int                         DevFD;
556    int                         OverRide;
557{
558    int                         Status = 0;
559    int                         Type = 0;
560    static ScsiQuery_t          Query;
561    int                         fd = -1;
562
563    if (!DevInfo || !DevFile) {
564        SImsg(SIM_DBG, "ScsiQuery: Bad parameters.");
565        return(-1);
566    }
567
568    if (DevFD < 0) {
569        /*
570         * We use O_RDWR because many OS's require Write perms
571         */
572        DevFD = fd = open(DevFile, O_RDWR|O_NDELAY|O_NONBLOCK);
573        if (fd < 0) {
574            SImsg(SIM_GERR, "%s: ScsiQuery: open for read failed: %s",
575                  DevFile, SYSERR);
576            return(-1);
577        }
578    }
579
580    (void) memset(&Query, 0, sizeof(Query));
581    Query.DevInfo = DevInfo;
582    Query.DevFile = DevFile;
583    Query.DevFD = DevFD;
584    Query.OverRide = OverRide;
585
586    /* Insure DevInfo->Name is valid */
587    if (!Query.DevInfo->Name)
588        Query.DevInfo->Name = DevFile;
589
590    /*
591     * We expect that after ScsiQueryInquire() DevInfo->Type will
592     * be correctly set.
593     */
594    if (ScsiQueryInquiry(&Query) < 0)
595        --Status;
596
597    /*
598     * For the rest of these, only try the Query if Type is not
599     * set or if the Type is set to an appropriate device type
600     */
601    Type = Query.DevInfo->Type;
602    if (!Type || Type == DT_DISKDRIVE || Type == DT_CDROM) {
603        if (ScsiQueryCapacity(&Query) < 0)
604            --Status;
605        if (ScsiQueryFormat(&Query) < 0)
606            --Status;
607        if (ScsiQueryGeometry(&Query) < 0)
608            --Status;
609    }
610    if (!Type || Type == DT_CDROM) {
611        if (ScsiQuerySpeed(&Query) < 0)
612            --Status;
613    }
614
615    /*
616     * If we opened the descriptor, then close it now
617     */
618    if (fd >= 0)
619        (void) close(fd);
620
621    /*
622     * If all Scsi*() functions returned error, we return error.
623     * If at least 1 function succeeded, we return success.
624     */
625    if (Status == -5)   /* XXX change to be count of ScsiQuery*() above */
626        return(-1);
627    else
628        return(0);
629}
Note: See TracBrowser for help on using the repository browser.