1 |
/* |
2 |
* scsidump.cpp - SCSI Dump (to see FreeBSD remappings) |
3 |
* Compile as (CAM version): gcc -I/sys -DCAM -o scsidump scsidump.cpp -lcam |
4 |
* (old SCSI version): gcc -o scsidump scsidump.cpp -lscsi |
5 |
* Copyright (C) 1999 Orlando Bassotto |
6 |
* |
7 |
* Basilisk II (C) 1997-2004 Christian Bauer |
8 |
* |
9 |
* This program is free software; you can redistribute it and/or modify |
10 |
* it under the terms of the GNU General Public License as published by |
11 |
* the Free Software Foundation; either version 2 of the License, or |
12 |
* (at your option) any later version. |
13 |
* |
14 |
* This program is distributed in the hope that it will be useful, |
15 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 |
* GNU General Public License for more details. |
18 |
* |
19 |
* You should have received a copy of the GNU General Public License |
20 |
* along with this program; if not, write to the Free Software |
21 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
22 |
* |
23 |
* History: |
24 |
* 29-Jun-1999 Started |
25 |
* 05-Jul-1999 Changed from array to queue removing the limit of 8 |
26 |
* devices. |
27 |
* Implemented old SCSI manager for FreeBSD 2.x. |
28 |
* (Note: This implementation have been never tested; |
29 |
* I don't own anymore a machine with FreeBSD 2.x, |
30 |
* so if something goes wrong, please mail me at |
31 |
* future@mediabit.net). |
32 |
*/ |
33 |
|
34 |
#include <sys/ioctl.h> |
35 |
#include <sys/types.h> |
36 |
#include <stdio.h> |
37 |
#include <stdlib.h> |
38 |
#include <string.h> |
39 |
#include <unistd.h> |
40 |
#include <fcntl.h> |
41 |
#include <ctype.h> |
42 |
#include <err.h> |
43 |
|
44 |
#ifdef CAM |
45 |
#include <cam/cam.h> |
46 |
#include <cam/cam_debug.h> |
47 |
#include <cam/cam_ccb.h> |
48 |
#include <cam/scsi/scsi_all.h> |
49 |
#include <cam/scsi/scsi_da.h> |
50 |
#include <cam/scsi/scsi_pass.h> |
51 |
#include <cam/scsi/scsi_message.h> |
52 |
#include <camlib.h> |
53 |
#else /* !CAM */ |
54 |
#include <sys/scsiio.h> |
55 |
#include <scsi.h> |
56 |
#endif /* !CAM */ |
57 |
|
58 |
#undef u_int8_t |
59 |
#define u_int8_t unsigned char |
60 |
|
61 |
typedef struct _SCSIDevice { |
62 |
int controller; // SCSI Controller |
63 |
int controller_bus; // SCSI Controller Bus |
64 |
char controller_name[33]; // SCSI Controller name |
65 |
int mac_unit; // Macintosh SCSI ID (remapped) |
66 |
int faked_controller; // "Faked" SCSI Controller (Always 0) |
67 |
int faked_unit; // "Faked" SCSI ID |
68 |
int unit; // Real SCSI ID |
69 |
int lun; // Real SCSI LUN |
70 |
u_int8_t vendor[16]; // SCSI Vendor |
71 |
u_int8_t product[48]; // SCSI Product |
72 |
u_int8_t revision[16]; // SCSI Revision |
73 |
char device[33]; // SCSI Device |
74 |
#ifdef CAM |
75 |
char pass_device[33]; // SCSI Pass Device |
76 |
#else /* !CAM */ |
77 |
int dev_fd; // Device File Descriptor |
78 |
#endif /* !CAM */ |
79 |
void* dev_ptr; // Pointer to CAM/SCSI structure |
80 |
bool enabled; // Device enabled ? |
81 |
struct _SCSIDevice* next; // Pointer to the next device |
82 |
} SCSIDevice; |
83 |
|
84 |
static int nDevices = 0; |
85 |
static SCSIDevice* Devices = NULL; |
86 |
|
87 |
inline static SCSIDevice* _GetSCSIDeviceByID(int id) |
88 |
{ |
89 |
SCSIDevice* aux = Devices; |
90 |
while(aux) { |
91 |
if(aux->faked_unit==id) { |
92 |
return aux; |
93 |
} |
94 |
aux = aux->next; |
95 |
} |
96 |
return NULL; |
97 |
} |
98 |
|
99 |
inline static SCSIDevice* _GetSCSIDeviceByIDLUN(int id, int lun) |
100 |
{ |
101 |
SCSIDevice* aux = Devices; |
102 |
while(aux) { |
103 |
if(aux->faked_unit==id&&aux->lun==lun) { |
104 |
return aux; |
105 |
} |
106 |
aux = aux->next; |
107 |
} |
108 |
return NULL; |
109 |
} |
110 |
|
111 |
inline static SCSIDevice* _GetSCSIDeviceByMacID(int id) |
112 |
{ |
113 |
SCSIDevice* aux = Devices; |
114 |
while(aux) { |
115 |
if(aux->mac_unit==id) { |
116 |
return aux; |
117 |
} |
118 |
aux = aux->next; |
119 |
} |
120 |
return NULL; |
121 |
} |
122 |
|
123 |
inline static SCSIDevice* _GetSCSIDeviceByMacIDLUN(int id, int lun) |
124 |
{ |
125 |
SCSIDevice* aux = Devices; |
126 |
while(aux) { |
127 |
if(aux->mac_unit==id&&aux->lun==lun) { |
128 |
return aux; |
129 |
} |
130 |
aux = aux->next; |
131 |
} |
132 |
return NULL; |
133 |
} |
134 |
|
135 |
inline static SCSIDevice* _AllocNewDevice() |
136 |
{ |
137 |
SCSIDevice* aux; |
138 |
|
139 |
aux = new SCSIDevice; |
140 |
if(aux==NULL) return NULL; |
141 |
memset(aux, 0, sizeof(SCSIDevice)); |
142 |
aux->next = Devices; |
143 |
Devices = aux; |
144 |
return aux; |
145 |
} |
146 |
|
147 |
/* |
148 |
* _Build_SCSI_Controller() |
149 |
* |
150 |
* This function builds a virtual SCSI Controller (Controller=0) |
151 |
* where keeps all the devices found, this is due the fact |
152 |
* I have two SCSI controllers in my PC. :-) |
153 |
* Use FreeBSD-SCSIDump in contrib/ to see how is remapped your |
154 |
* SCSI device (only if you have more than one controller, |
155 |
* that's for sure :-). |
156 |
*/ |
157 |
|
158 |
#define GET_FREE_ID(id) \ |
159 |
{ \ |
160 |
for(int x=0;x<32;x++) { \ |
161 |
if(!(busyIDs&(1<<(x+1)))) { \ |
162 |
id = x; \ |
163 |
break; \ |
164 |
} \ |
165 |
} \ |
166 |
} |
167 |
|
168 |
static void _Build_SCSI_Controller() |
169 |
{ |
170 |
unsigned int id = 0; |
171 |
unsigned long long busyIDs = 0x0ll; |
172 |
SCSIDevice* aux, * dev; |
173 |
|
174 |
// What IDs are busy? |
175 |
dev = Devices; |
176 |
while(dev) { |
177 |
dev->enabled = false; |
178 |
dev->faked_controller = 0; |
179 |
dev->faked_unit = dev->unit; |
180 |
busyIDs |= (1 << (dev->unit+1)); |
181 |
dev = dev->next; |
182 |
} |
183 |
|
184 |
// Find out the duplicate IDs and change them |
185 |
dev = Devices, aux = NULL; |
186 |
while(dev) { |
187 |
aux = dev; |
188 |
while(aux) { |
189 |
SCSIDevice* dev1, * dev2; |
190 |
|
191 |
dev1 = dev, dev2 = aux; |
192 |
|
193 |
if(dev1->controller!=dev2->controller&& |
194 |
dev1->unit==dev2->unit) { |
195 |
int free_id; |
196 |
GET_FREE_ID(free_id); |
197 |
busyIDs |= (1<<(free_id+1)); |
198 |
dev1->faked_unit = free_id; |
199 |
} |
200 |
aux = aux->next; |
201 |
} |
202 |
dev = dev->next; |
203 |
} |
204 |
|
205 |
// Now reorder the queue |
206 |
dev = Devices; |
207 |
while(dev) { |
208 |
aux = dev; |
209 |
while(aux) { |
210 |
SCSIDevice* dev1, * dev2; |
211 |
|
212 |
dev1 = dev, dev2 = aux; |
213 |
/* |
214 |
if(dev1->faked_unit>dev2->faked_unit) { |
215 |
SCSIDevice tmp; |
216 |
|
217 |
memcpy(&tmp, dev1, sizeof(SCSIDevice)); |
218 |
memcpy(dev1, dev2, sizeof(SCSIDevice)); |
219 |
memcpy(dev2, &tmp, sizeof(SCSIDevice)); |
220 |
} |
221 |
*/ |
222 |
aux = aux->next; |
223 |
} |
224 |
dev = dev->next; |
225 |
} |
226 |
} |
227 |
|
228 |
#define SCSIReset() |
229 |
|
230 |
/* |
231 |
* Initialization |
232 |
*/ |
233 |
|
234 |
void SCSIInit(void) |
235 |
{ |
236 |
// Find the SCSI hosts in the system |
237 |
// Filling out the SCSIDevices queue. |
238 |
// Stolen from camcontrol.c |
239 |
int bufsize, fd; |
240 |
int need_close = 0; |
241 |
int error = 0; |
242 |
int skip_device = 0; |
243 |
SCSIDevice* Dev, * dev, * PrevDev = NULL; |
244 |
|
245 |
nDevices = 0; |
246 |
|
247 |
#ifdef CAM |
248 |
union ccb ccb; |
249 |
|
250 |
if ((fd = open(XPT_DEVICE, O_RDWR)) == -1) { |
251 |
fprintf(stderr, "Cannot open CAM device: %s\n", XPT_DEVICE); |
252 |
goto no_scsi; |
253 |
} |
254 |
|
255 |
memset(&(&ccb.ccb_h)[1], 0, sizeof(struct ccb_dev_match)-sizeof(struct ccb_hdr)); |
256 |
ccb.ccb_h.func_code = XPT_DEV_MATCH; |
257 |
bufsize = sizeof(struct dev_match_result) * 100; |
258 |
ccb.cdm.match_buf_len = bufsize; |
259 |
ccb.cdm.matches = (struct dev_match_result *)malloc(bufsize); |
260 |
ccb.cdm.num_matches = 0; |
261 |
|
262 |
ccb.cdm.num_patterns = 0; |
263 |
ccb.cdm.pattern_buf_len = 0; |
264 |
|
265 |
do { |
266 |
Dev = _AllocNewDevice(); |
267 |
if(ioctl(fd, CAMIOCOMMAND, &ccb)==-1) { |
268 |
fprintf(stderr, "Error sending CAMIOCOMMAND ioctl\n"); |
269 |
return; |
270 |
} |
271 |
|
272 |
if((ccb.ccb_h.status != CAM_REQ_CMP) |
273 |
|| ((ccb.cdm.status != CAM_DEV_MATCH_LAST) |
274 |
&& (ccb.cdm.status != CAM_DEV_MATCH_MORE))) { |
275 |
fprintf(stderr, "Got CAM error %#x, CDM error %d\n", |
276 |
ccb.ccb_h.status, ccb.cdm.status); |
277 |
return; |
278 |
} |
279 |
|
280 |
char current_controller_name[33]; |
281 |
int current_controller = -1; |
282 |
for(int i=0;i<ccb.cdm.num_matches;i++) { |
283 |
switch(ccb.cdm.matches[i].type) { |
284 |
case DEV_MATCH_BUS: |
285 |
{ |
286 |
struct bus_match_result* bus_result; |
287 |
|
288 |
bus_result = &ccb.cdm.matches[i].result.bus_result; |
289 |
|
290 |
if(bus_result->path_id==-1) break; |
291 |
Dev->controller = bus_result->path_id; |
292 |
snprintf(Dev->controller_name, sizeof(Dev->controller_name), "%s%d", |
293 |
bus_result->dev_name, |
294 |
bus_result->unit_number); |
295 |
strncpy(current_controller_name, Dev->controller_name, sizeof(current_controller_name)); |
296 |
current_controller = Dev->controller; |
297 |
Dev->controller_bus = bus_result->bus_id; |
298 |
break; |
299 |
} |
300 |
case DEV_MATCH_DEVICE: |
301 |
{ |
302 |
struct device_match_result* dev_result; |
303 |
char tmpstr[256]; |
304 |
|
305 |
dev_result = &ccb.cdm.matches[i].result.device_result; |
306 |
if(current_controller==-1||dev_result->target_id==-1) { |
307 |
skip_device = 1; |
308 |
break; |
309 |
} |
310 |
else skip_device = 0; |
311 |
|
312 |
cam_strvis(Dev->vendor, (u_int8_t*)dev_result->inq_data.vendor, |
313 |
sizeof(dev_result->inq_data.vendor), |
314 |
sizeof(Dev->vendor)); |
315 |
cam_strvis(Dev->product, (u_int8_t*)dev_result->inq_data.product, |
316 |
sizeof(dev_result->inq_data.product), |
317 |
sizeof(Dev->product)); |
318 |
cam_strvis(Dev->revision, (u_int8_t*)dev_result->inq_data.revision, |
319 |
sizeof(dev_result->inq_data.revision), |
320 |
sizeof(Dev->revision)); |
321 |
strncpy(Dev->controller_name, current_controller_name, sizeof(Dev->controller_name)); |
322 |
Dev->controller = current_controller; |
323 |
Dev->unit = dev_result->target_id; |
324 |
Dev->lun = dev_result->target_lun; |
325 |
break; |
326 |
} |
327 |
case DEV_MATCH_PERIPH: |
328 |
{ |
329 |
struct periph_match_result* periph_result; |
330 |
|
331 |
periph_result = &ccb.cdm.matches[i].result.periph_result; |
332 |
|
333 |
if(skip_device != 0) break; |
334 |
|
335 |
if(need_close==1) { |
336 |
snprintf(Dev->device, sizeof(Dev->device), "%s%d*", |
337 |
periph_result->periph_name, |
338 |
periph_result->unit_number); |
339 |
need_close = 0; |
340 |
} |
341 |
else if(need_close==0) { |
342 |
snprintf(Dev->pass_device, sizeof(Dev->pass_device), "%s%d", |
343 |
periph_result->periph_name, |
344 |
periph_result->unit_number); |
345 |
need_close++; |
346 |
break; |
347 |
} |
348 |
else { |
349 |
need_close = 0; |
350 |
} |
351 |
PrevDev = Dev; |
352 |
Dev = _AllocNewDevice(); |
353 |
break; |
354 |
} |
355 |
} |
356 |
} |
357 |
} while (ccb.ccb_h.status == CAM_REQ_CMP |
358 |
&& ccb.cdm.status == CAM_DEV_MATCH_MORE); |
359 |
|
360 |
/* Remove last one (ugly coding) */ |
361 |
Devices = PrevDev; |
362 |
delete Dev; |
363 |
end_loop: |
364 |
close(fd); |
365 |
#else /* !CAM */ |
366 |
/* |
367 |
* FreeBSD 2.x SCSI management is quiet different and |
368 |
* unfortunatly not flexible as CAM library in FreeBSD 3.x... |
369 |
* I only scan for the first bus, LUN 0, and the |
370 |
* first 8 devices only. |
371 |
*/ |
372 |
u_char* inq_buf; |
373 |
scsireq_t* scsireq; |
374 |
struct scsi_addr scsi; |
375 |
int ssc_fd; |
376 |
|
377 |
if((ssc_fd=open("/dev/ssc", O_RDWR))==-1) { |
378 |
fprintf(stderr, "Cannot open SCSI manager: /dev/ssc\n"); |
379 |
SCSIReset(); |
380 |
return; |
381 |
} |
382 |
|
383 |
inq_buf = (u_char*)malloc(96); |
384 |
if(inq_buf==NULL) { |
385 |
perror("malloc failed"); |
386 |
SCSIReset(); |
387 |
return; |
388 |
} |
389 |
|
390 |
scsireq = scsireq_build((scsireq_t*)dev->dev_ptr, |
391 |
96, inq_buf, SCCMD_READ, |
392 |
"12 0 0 0 v 0", 96); |
393 |
|
394 |
addr.scbus = 0; |
395 |
addr.lun = 0; |
396 |
|
397 |
for(int n=0;n<8;n++) { |
398 |
addr.target = n; |
399 |
|
400 |
if(ioctl(ssc_fd, SCIOCADDR, &addr) != -1) { |
401 |
Dev = _AllocNewDevice(); |
402 |
Dev->controller = addr.scbus; |
403 |
Dev->lun = addr.lun; |
404 |
Dev->unit = addr.target; |
405 |
|
406 |
struct scsi_devinfo devInfo; |
407 |
devInfo.addr = addr; |
408 |
if(ioctl(ssc_fd, SCIOCGETDEVINFO, &devInfo) != -1) { |
409 |
strncpy(Dev->device, devInfo.devname, sizeof(Dev->device)); |
410 |
} |
411 |
strncpy(Dev->controller_name, "FreeBSD 2.x SCSI Manager", sizeof(Dev->controller_name)); |
412 |
if(scsireq_enter(ssc_fd, scsireq)!=-1) { |
413 |
Dev->vendor[sizeof(Dev->vendor)-1] = 0; |
414 |
Dev->product[sizeof(Dev->product)-1] = 0; |
415 |
Dev->revision[sizeof(Dev->revision)-1] = 0; |
416 |
|
417 |
scsireq_decode(scsireq, "s8 c8 c16 c4", |
418 |
Dev->vendor, Dev->product, Dev->revision); |
419 |
} |
420 |
} |
421 |
} |
422 |
free(inq_buf); |
423 |
close(ssc_fd); |
424 |
#endif /* !CAM */ |
425 |
_Build_SCSI_Controller(); |
426 |
|
427 |
// Print out the periph with ID:LUNs |
428 |
fprintf(stderr, "Device RealID FkdID\n"); |
429 |
fprintf(stderr, "----------------------------------------------\n"); |
430 |
// 012345678901234567890123456789012 0:0:0 0/0 |
431 |
dev = Devices; |
432 |
while(dev) { |
433 |
char tmp[40]; |
434 |
snprintf(tmp, sizeof(tmp), "%s %s %s", |
435 |
dev->vendor, |
436 |
dev->product, |
437 |
dev->revision); |
438 |
fprintf(stderr, "%-33s %d:%d:%d %d/%d\n", |
439 |
tmp, dev->controller, dev->unit, dev->lun, |
440 |
dev->faked_unit, dev->lun); |
441 |
dev = dev->next; |
442 |
} |
443 |
|
444 |
no_scsi: |
445 |
// Reset SCSI bus |
446 |
SCSIReset(); |
447 |
} |
448 |
|
449 |
|
450 |
/* |
451 |
* Deinitialization |
452 |
*/ |
453 |
|
454 |
void SCSIExit(void) |
455 |
{ |
456 |
SCSIDevice* aux; |
457 |
while(Devices) { |
458 |
aux = Devices->next; |
459 |
if(Devices->dev_ptr!=NULL) { |
460 |
#ifdef CAM |
461 |
cam_close_device((struct cam_device*)Devices->dev_ptr); |
462 |
#else /* !CAM */ |
463 |
free(Devices->dev_ptr); // Is this right? |
464 |
close(Devices->dev_fd); // And this one? |
465 |
#endif /* !CAM */ |
466 |
} |
467 |
delete Devices; |
468 |
Devices = aux; |
469 |
} |
470 |
nDevices = 0; |
471 |
} |
472 |
|
473 |
int main() |
474 |
{ |
475 |
SCSIInit(); |
476 |
SCSIExit(); |
477 |
return 0; |
478 |
} |