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 |
---|
10 | static 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 | */ |
---|
24 | static 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 | */ |
---|
61 | extern 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 | */ |
---|
94 | extern 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 | */ |
---|
236 | extern 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 | */ |
---|
274 | extern 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 | */ |
---|
310 | extern 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 | */ |
---|
341 | extern 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 | */ |
---|
379 | extern 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 | */ |
---|
426 | extern 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 | */ |
---|
472 | extern 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 | */ |
---|
500 | extern 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 | */ |
---|
552 | extern 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 | } |
---|