ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/FreeBSD/scsidump.cpp
Revision: 1.7
Committed: 2008-01-01T09:40:33Z (16 years, 11 months ago) by gbeauche
Branch: MAIN
CVS Tags: HEAD
Changes since 1.6: +1 -1 lines
Log Message:
Happy New Year!

File Contents

# Content
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-2008 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 }