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

# User Rev Content
1 cebix 1.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 gbeauche 1.7 * Basilisk II (C) 1997-2008 Christian Bauer
8 cebix 1.1 *
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     }