ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/FreeBSD/scsi_freebsd.cpp
Revision: 1.1.1.1 (vendor branch)
Committed: 1999-10-03T14:16:25Z (25 years, 2 months ago) by cebix
Branch: cebix
CVS Tags: release-0_7-2, snapshot-21101999, start, snapshot-22121999, release-0_8-1, snapshot-02111999
Changes since 1.1: +0 -0 lines
Log Message:
Imported sources

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * scsi_freebsd.cpp - SCSI Manager, FreeBSD SCSI Driver implementation
3     * Copyright (C) 1999 Orlando Bassotto
4     *
5     * Basilisk II (C) 1997-1999 Christian Bauer
6     *
7     * This program is free software; you can redistribute it and/or modify
8     * it under the terms of the GNU General Public License as published by
9     * the Free Software Foundation; either version 2 of the License, or
10     * (at your option) any later version.
11     *
12     * This program is distributed in the hope that it will be useful,
13     * but WITHOUT ANY WARRANTY; without even the implied warranty of
14     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15     * GNU General Public License for more details.
16     *
17     * You should have received a copy of the GNU General Public License
18     * along with this program; if not, write to the Free Software
19     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20     *
21     * History:
22     * 29-Jun-1999 Started
23     * 05-Jul-1999 Changed from array to queue removing the limit of 8
24     * devices.
25     * Implemented old SCSI management for FreeBSD 2.x.
26     * (Note: This implementation hasn't been tested;
27     * I don't own anymore a machine with FreeBSD 2.x,
28     * so if something goes wrong, please mail me to
29     * future@mediabit.net).
30     */
31    
32     #include <sys/ioctl.h>
33     #include <sys/types.h>
34     #include <stdio.h>
35     #include <stdlib.h>
36     #include <string.h>
37     #include <unistd.h>
38     #include <fcntl.h>
39     #include <ctype.h>
40     #include <errno.h>
41     #include <err.h>
42    
43     #ifdef CAM
44     #include <cam/cam.h>
45     #include <cam/cam_debug.h>
46     #include <cam/cam_ccb.h>
47     #include <cam/scsi/scsi_all.h>
48     #include <cam/scsi/scsi_da.h>
49     #include <cam/scsi/scsi_pass.h>
50     #include <cam/scsi/scsi_message.h>
51     #include <camlib.h>
52     #else /* !CAM */
53     #include <sys/scsiio.h>
54     #include <scsi.h>
55     #endif /* !CAM */
56    
57     #include "sysdeps.h"
58     #include "main.h"
59     #include "prefs.h"
60     #include "user_strings.h"
61     #include "scsi.h"
62    
63     #define DEBUG 0
64     #include "debug.h"
65    
66    
67     #undef u_int8_t
68     #define u_int8_t unsigned char
69    
70     typedef struct _SCSIDevice {
71     int controller; // SCSI Controller
72     int controller_bus; // SCSI Controller Bus
73     char controller_name[33]; // SCSI Controller name
74     int mac_unit; // Macintosh SCSI ID (remapped)
75     int faked_controller; // "Faked" SCSI Controller (Always 0)
76     int faked_unit; // "Faked" SCSI ID
77     int unit; // Real SCSI ID
78     int lun; // Real SCSI LUN
79     u_int8_t vendor[16]; // SCSI Vendor
80     u_int8_t product[48]; // SCSI Product
81     u_int8_t revision[16]; // SCSI Revision
82     char device[33]; // SCSI Device
83     #ifdef CAM
84     char pass_device[33]; // SCSI Pass Device
85     #else /* !CAM */
86     int dev_fd; // Device File Descriptor
87     #endif /* !CAM */
88     void* dev_ptr; // Pointer to CAM/SCSI structure
89     bool enabled; // Device enabled ?
90     struct _SCSIDevice* next; // Pointer to the next device
91     } SCSIDevice;
92    
93     static int nDevices = 0;
94     static SCSIDevice* Devices = NULL;
95    
96     static uint32 buffer_size;
97     static uint8* buffer = NULL;
98    
99     static uint8 the_cmd[12];
100     static int the_cmd_len;
101    
102     static SCSIDevice* CurrentDevice = NULL;
103    
104     inline static SCSIDevice* _GetSCSIDeviceByID(int id)
105     {
106     SCSIDevice* aux = Devices;
107     while(aux) {
108     if(aux->faked_unit==id) {
109     return aux;
110     }
111     aux = aux->next;
112     }
113     return NULL;
114     }
115    
116     inline static SCSIDevice* _GetSCSIDeviceByIDLUN(int id, int lun)
117     {
118     SCSIDevice* aux = Devices;
119     while(aux) {
120     if(aux->faked_unit==id&&aux->lun==lun) {
121     return aux;
122     }
123     aux = aux->next;
124     }
125     return NULL;
126     }
127    
128     inline static SCSIDevice* _GetSCSIDeviceByMacID(int id)
129     {
130     SCSIDevice* aux = Devices;
131     while(aux) {
132     if(aux->mac_unit==id) {
133     return aux;
134     }
135     aux = aux->next;
136     }
137     return NULL;
138     }
139    
140     inline static SCSIDevice* _GetSCSIDeviceByMacIDLUN(int id, int lun)
141     {
142     SCSIDevice* aux = Devices;
143     while(aux) {
144     if(aux->mac_unit==id&&aux->lun==lun) {
145     return aux;
146     }
147     aux = aux->next;
148     }
149     return NULL;
150     }
151    
152     inline static SCSIDevice* _AllocNewDevice()
153     {
154     SCSIDevice* aux;
155    
156     aux = new SCSIDevice;
157     if(aux==NULL) return NULL;
158     memset(aux, 0, sizeof(SCSIDevice));
159     aux->next = Devices;
160     Devices = aux;
161     return aux;
162     }
163    
164     #ifdef CAM
165     inline static struct cam_device* _GetCurrentSCSIDevice()
166     {
167     if(CurrentDevice==NULL) return NULL;
168    
169     return (struct cam_device*)CurrentDevice->dev_ptr;
170     }
171     #else /* !CAM */
172     inline static struct scsireq* _GetCurrentSCSIDevice()
173     {
174     if(CurrentDevice==NULL) return NULL;
175    
176     return (struct scsireq*)CurrentDevice->dev_ptr;
177     }
178     #endif /* !CAM */
179    
180     /*
181     * _Build_SCSI_Controller()
182     *
183     * This function builds a virtual SCSI Controller (Controller=0)
184     * where keeps all the devices found, this is due the fact
185     * I have two SCSI controllers in my PC. :-)
186     * Use scsidump in contrib/ to see how is remapped your
187     * SCSI device (only if you have more than one controller,
188     * that's for sure :-).
189     * If you have only one controller, remapping does not take act.
190     */
191    
192     #define GET_FREE_ID(id) \
193     { \
194     for(int x=0;x<32;x++) { \
195     if(!(busyIDs&(1<<(x+1)))) { \
196     id = x; \
197     break; \
198     } \
199     } \
200     }
201    
202     static void _Build_SCSI_Controller()
203     {
204     unsigned int id = 0;
205     unsigned long long busyIDs = 0x0ll;
206     SCSIDevice* aux, * dev;
207    
208     // What IDs are busy?
209     dev = Devices;
210     while(dev) {
211     dev->enabled = false;
212     dev->faked_controller = 0;
213     dev->faked_unit = dev->unit;
214     busyIDs |= (1 << (dev->unit+1));
215     dev = dev->next;
216     }
217    
218     // Find out the duplicate IDs and remap them
219     dev = Devices, aux = NULL;
220     while(dev) {
221     aux = dev;
222     while(aux) {
223     SCSIDevice* dev1, * dev2;
224    
225     dev1 = dev, dev2 = aux;
226    
227     if(dev1->controller!=dev2->controller&&
228     dev1->unit==dev2->unit) {
229     int free_id;
230     GET_FREE_ID(free_id);
231     busyIDs |= (1<<(free_id+1));
232     dev1->faked_unit = free_id;
233     }
234     aux = aux->next;
235     }
236     dev = dev->next;
237     }
238    
239     // Now reorder the queue
240     #if 0
241     dev = Devices;
242     while(dev) {
243     aux = dev;
244     while(aux) {
245     SCSIDevice* dev1, * dev2;
246    
247     dev1 = dev, dev2 = aux;
248     if(dev1->faked_unit>dev2->faked_unit) {
249     SCSIDevice tmp;
250    
251     memcpy(&tmp, dev1, sizeof(SCSIDevice));
252     memcpy(dev1, dev2, sizeof(SCSIDevice));
253     memcpy(dev2, &tmp, sizeof(SCSIDevice));
254     }
255     aux = aux->next;
256     }
257     dev = dev->next;
258     }
259     #endif
260    
261     // Now open the selected SCSI devices :-)
262     for(int n=0;n<8;n++) {
263     char tmp[25];
264    
265     snprintf(tmp, sizeof(tmp), "scsi%d", n);
266     const char* scsi = PrefsFindString(tmp);
267     if(scsi) {
268     int id, lun;
269    
270     // The format is: RemappedID (or FakedID)/LUN
271     sscanf(scsi, "%d/%d", &id, &lun);
272    
273     SCSIDevice* dev = _GetSCSIDeviceByIDLUN(id, lun);
274     if(dev==NULL) continue;
275     dev->enabled = true;
276     dev->mac_unit = n;
277    
278     #ifdef CAM
279     struct cam_device* cam;
280    
281     cam = cam_open_btl(dev->controller,
282     dev->unit,
283     dev->lun, O_RDWR, NULL);
284     if(cam==NULL) {
285     fprintf(stderr, "Failed to open %d:%d:%d = %s!!!\n",
286     dev->controller, dev->unit, dev->lun,
287     cam_errbuf);
288     }
289     dev->dev_ptr = (void*)cam;
290     #else /* !CAM */
291     dev->dev_fd = scsi_open(dev->device, O_RDWR);
292     if(dev->dev_fd<0) {
293     perror("Failed to open %d:%d:%d");
294     }
295     else {
296     dev->dev_ptr = (void*)scsireq_new();
297     }
298     #endif /* !CAM */
299     }
300     }
301     }
302    
303    
304     /*
305     * Initialization
306     */
307    
308     void SCSIInit(void)
309     {
310     // Finds the SCSI hosts in the system filling the SCSIDevices queue.
311     // "Stolen" from camcontrol.c
312     // Copyright (C) 1997-99 Kenneth D. Merry
313     // Old SCSI detection "stolen" from scsi.c
314     // Copyright (C) 1993 Julian Elischer
315     //
316     int bufsize, fd;
317     int need_close = 0;
318     int error = 0;
319     int skip_device = 0;
320     SCSIDevice* Dev, * dev, * PrevDev = NULL;
321    
322     nDevices = 0;
323    
324     if(PrefsFindBool("noscsi"))
325     goto no_scsi;
326    
327     #ifdef CAM
328     union ccb ccb;
329     if ((fd = open(XPT_DEVICE, O_RDWR)) == -1) {
330     fprintf(stderr, "WARNING: Cannot open CAM device %s (%s)\n", XPT_DEVICE, strerror(errno));
331     goto no_scsi;
332     }
333    
334     memset(&(&ccb.ccb_h)[1], 0, sizeof(struct ccb_dev_match)-sizeof(struct ccb_hdr));
335     ccb.ccb_h.func_code = XPT_DEV_MATCH;
336     bufsize = sizeof(struct dev_match_result) * 100;
337     ccb.cdm.match_buf_len = bufsize;
338     ccb.cdm.matches = (struct dev_match_result *)malloc(bufsize);
339     ccb.cdm.num_matches = 0;
340    
341     ccb.cdm.num_patterns = 0;
342     ccb.cdm.pattern_buf_len = 0;
343    
344     do {
345     Dev = _AllocNewDevice();
346     if(ioctl(fd, CAMIOCOMMAND, &ccb)==-1) {
347     fprintf(stderr, "Error sending CAMIOCOMMAND ioctl\n");
348     return;
349     }
350    
351     if((ccb.ccb_h.status != CAM_REQ_CMP)
352     || ((ccb.cdm.status != CAM_DEV_MATCH_LAST)
353     && (ccb.cdm.status != CAM_DEV_MATCH_MORE))) {
354     fprintf(stderr, "Got CAM error %#x, CDM error %d\n",
355     ccb.ccb_h.status, ccb.cdm.status);
356     return;
357     }
358    
359     char current_controller_name[33];
360     int current_controller = -1;
361     for(int i=0;i<ccb.cdm.num_matches;i++) {
362     switch(ccb.cdm.matches[i].type) {
363     case DEV_MATCH_BUS:
364     {
365     struct bus_match_result* bus_result;
366    
367     bus_result = &ccb.cdm.matches[i].result.bus_result;
368    
369     if(bus_result->path_id==-1) break;
370     Dev->controller = bus_result->path_id;
371     snprintf(Dev->controller_name, sizeof(Dev->controller_name), "%s%d",
372     bus_result->dev_name,
373     bus_result->unit_number);
374     strncpy(current_controller_name, Dev->controller_name, sizeof(current_controller_name));
375     current_controller = Dev->controller;
376     Dev->controller_bus = bus_result->bus_id;
377     break;
378     }
379     case DEV_MATCH_DEVICE:
380     {
381     struct device_match_result* dev_result;
382     char tmpstr[256];
383    
384     dev_result = &ccb.cdm.matches[i].result.device_result;
385     if(current_controller==-1||dev_result->target_id==-1) {
386     skip_device = 1;
387     break;
388     }
389     else skip_device = 0;
390    
391     cam_strvis(Dev->vendor, (u_int8_t*)dev_result->inq_data.vendor,
392     sizeof(dev_result->inq_data.vendor),
393     sizeof(Dev->vendor));
394     cam_strvis(Dev->product, (u_int8_t*)dev_result->inq_data.product,
395     sizeof(dev_result->inq_data.product),
396     sizeof(Dev->product));
397     cam_strvis(Dev->revision, (u_int8_t*)dev_result->inq_data.revision,
398     sizeof(dev_result->inq_data.revision),
399     sizeof(Dev->revision));
400     strncpy(Dev->controller_name, current_controller_name, sizeof(Dev->controller_name));
401     Dev->controller = current_controller;
402     Dev->unit = dev_result->target_id;
403     Dev->lun = dev_result->target_lun;
404     break;
405     }
406     case DEV_MATCH_PERIPH:
407     {
408     struct periph_match_result* periph_result;
409    
410     periph_result = &ccb.cdm.matches[i].result.periph_result;
411    
412     if(skip_device != 0) break;
413    
414     if(need_close==1) {
415     snprintf(Dev->device, sizeof(Dev->device), "%s%d*",
416     periph_result->periph_name,
417     periph_result->unit_number);
418     need_close = 0;
419     }
420     else if(need_close==0) {
421     snprintf(Dev->pass_device, sizeof(Dev->pass_device), "%s%d",
422     periph_result->periph_name,
423     periph_result->unit_number);
424     need_close++;
425     break;
426     }
427     else {
428     need_close = 0;
429     }
430     PrevDev = Dev;
431     Dev = _AllocNewDevice();
432     break;
433     }
434     }
435     }
436     } while (ccb.ccb_h.status == CAM_REQ_CMP
437     && ccb.cdm.status == CAM_DEV_MATCH_MORE);
438    
439     /* Remove last one (ugly coding) */
440     Devices = PrevDev;
441     delete Dev;
442     end_loop:
443     close(fd);
444     #else /* !CAM */
445     /*
446     * FreeBSD 2.x SCSI management is quiet different and
447     * unfortunatly not flexible as CAM library in FreeBSD 3.x...
448     * I probe only the first bus, LUN 0, and the
449     * first 8 devices only.
450     */
451     u_char* inq_buf;
452     scsireq_t* scsireq;
453     struct scsi_addr scsi;
454     int ssc_fd;
455    
456     if((ssc_fd=open("/dev/ssc", O_RDWR))==-1) {
457     fprintf(stderr, "Cannot open SCSI manager: /dev/ssc\n");
458     SCSIReset();
459     return;
460     }
461    
462     inq_buf = (u_char*)malloc(96);
463     if(inq_buf==NULL) {
464     perror("malloc failed");
465     SCSIReset();
466     return;
467     }
468    
469     scsireq = scsireq_build((scsireq_t*)dev->dev_ptr,
470     96, inq_buf, SCCMD_READ,
471     "12 0 0 0 v 0", 96);
472    
473     addr.scbus = 0;
474     addr.lun = 0;
475    
476     for(int n=0;n<8;n++) {
477     addr.target = n;
478    
479     if(ioctl(ssc_fd, SCIOCADDR, &addr) != -1) {
480     Dev = _AllocNewDevice();
481     Dev->controller = addr.scbus;
482     Dev->lun = addr.lun;
483     Dev->unit = addr.target;
484    
485     struct scsi_devinfo devInfo;
486     devInfo.addr = addr;
487     if(ioctl(ssc_fd, SCIOCGETDEVINFO, &devInfo) != -1) {
488     strncpy(Dev->device, devInfo.devname, sizeof(Dev->device));
489     }
490     strncpy(Dev->controller_name, "FreeBSD 2.x SCSI Manager", sizeof(Dev->controller_name));
491     if(scsireq_enter(ssc_fd, scsireq)!=-1) {
492     Dev->vendor[sizeof(Dev->vendor)-1] = 0;
493     Dev->product[sizeof(Dev->product)-1] = 0;
494     Dev->revision[sizeof(Dev->revision)-1] = 0;
495    
496     scsireq_decode(scsireq, "s8 c8 c16 c4",
497     Dev->vendor, Dev->product, Dev->revision);
498     }
499     }
500     }
501     free(inq_buf);
502     close(ssc_fd);
503     #endif /* !CAM */
504     _Build_SCSI_Controller();
505    
506     // Print out the periph with ID:LUNs
507     fprintf(stderr, "Device RealID FkdID MacID Enabled\n");
508     fprintf(stderr, "-------------------------------------------------------------\n");
509     // 012345678901234567890123456789012 0:0:0 0/0 0:0 Yes
510     dev = Devices;
511     while(dev) {
512     char tmp[40];
513     snprintf(tmp, sizeof(tmp), "%s %s %s",
514     dev->vendor,
515     dev->product,
516     dev->revision);
517     fprintf(stderr, "%-33s %d:%d:%d %d/%d %d:%d %s\n",
518     tmp, dev->controller, dev->unit, dev->lun,
519     dev->faked_unit, dev->lun,
520     dev->mac_unit, dev->lun, dev->enabled?"Yes":"No");
521     dev = dev->next;
522     }
523    
524     no_scsi:
525     // Reset SCSI bus
526     SCSIReset();
527     }
528    
529    
530     /*
531     * Deinitialization
532     */
533    
534     void SCSIExit(void)
535     {
536     SCSIDevice* aux;
537     while(Devices) {
538     aux = Devices->next;
539     if(Devices->dev_ptr!=NULL) {
540     #ifdef CAM
541     cam_close_device((struct cam_device*)Devices->dev_ptr);
542     #else /* !CAM */
543     free(Devices->dev_ptr); // Is this right?
544     close(Devices->dev_fd); // And this one?
545     #endif /* !CAM */
546     }
547     delete Devices;
548     Devices = aux;
549     }
550     nDevices = 0;
551     }
552    
553    
554     /*
555     * Set SCSI command to be sent by scsi_send_cmd()
556     */
557    
558     void scsi_set_cmd(int cmd_length, uint8 *cmd)
559     {
560     the_cmd_len = cmd_length;
561     memset(the_cmd, 0, sizeof(the_cmd));
562     memcpy(the_cmd, cmd, the_cmd_len);
563     }
564    
565    
566     /*
567     * Check for presence of SCSI target
568     */
569    
570     bool scsi_is_target_present(int id)
571     {
572     return (_GetSCSIDeviceByMacID(id)!=NULL&&_GetSCSIDeviceByMacID(id)->enabled);
573     }
574    
575    
576     /*
577     * Set SCSI target (returns false on error)
578     */
579    
580     bool scsi_set_target(int id, int lun)
581     {
582     SCSIDevice* dev;
583    
584     dev = _GetSCSIDeviceByMacIDLUN(id, lun);
585     if(dev==NULL) return false;
586     CurrentDevice = dev;
587     return true;
588     }
589    
590    
591     /*
592     * Send SCSI command to active target (scsi_set_command() must have been called),
593     * read/write data according to S/G table (returns false on error)
594     */
595    
596     static bool try_buffer(int size)
597     {
598     if(size <= buffer_size) {
599     return true;
600     }
601    
602     D(bug("Allocating buffer of %d bytes.\n", size));
603     uint8* new_buffer = (uint8*)valloc(size);
604     if(new_buffer==NULL) {
605     return false;
606     }
607     if(buffer!=NULL) free(buffer);
608     buffer = new_buffer;
609     buffer_size = size;
610     return true;
611     }
612    
613     bool scsi_send_cmd(size_t data_length, bool reading, int sg_size, uint8 **sg_ptr, uint32 *sg_len, uint16 *stat, uint32 timeout)
614     {
615     int value = 0;
616     #ifdef CAM
617     #ifdef VERBOSE_CAM_DEBUG
618     D(bug("Sending command %x (len=%d) to SCSI Device %d:%d:%d\n", the_cmd[0],
619     the_cmd_len,
620     CurrentDevice->controller,
621     CurrentDevice->unit,
622     CurrentDevice->lun));
623     D(bug("DataLength: %d\n", data_length));
624     D(bug("Reading: %d\n", reading));
625     D(bug("SG Size: %d\n", sg_size));
626     D(bug("Timeout: %d\n", timeout));
627     #endif /* VERBOSE_CAM_DEBUG */
628     #endif /* CAM */
629     if(!try_buffer(data_length)) {
630     char str[256];
631     sprintf(str, GetString(STR_SCSI_BUFFER_ERR), data_length);
632     ErrorAlert(str);
633     return false;
634     }
635    
636     if(!reading) {
637     uint8* buffer_ptr = buffer;
638     for(int i=0;i<sg_size;i++) {
639     uint32 len = sg_len[i];
640     memcpy(buffer, sg_ptr[i], len);
641     buffer_ptr += len;
642     }
643     }
644    
645     if(the_cmd[0] == 0x03) {
646     // faked cmd
647     *stat = 0;
648     return true;
649     }
650    
651    
652     #ifdef CAM
653     struct cam_device* device = _GetCurrentSCSIDevice();
654     if(device==NULL) return false;
655    
656     union ccb ccb;
657    
658     memset(&ccb, 0, sizeof(ccb));
659    
660     int dir_flags = CAM_DIR_NONE;
661     if(data_length>0) {
662     dir_flags = reading?CAM_DIR_IN:CAM_DIR_OUT;
663     }
664    
665     ccb.ccb_h.path_id = CurrentDevice->controller;
666     ccb.ccb_h.target_id = CurrentDevice->unit;
667     ccb.ccb_h.target_lun = CurrentDevice->lun;
668    
669     cam_fill_csio(&ccb.csio,
670     0,
671     NULL,
672     dir_flags,
673     MSG_SIMPLE_Q_TAG,
674     (u_int8_t*)buffer,
675     data_length,
676     SSD_FULL_SIZE,
677     the_cmd_len,
678     (timeout?timeout:50)*1000);
679    
680     ccb.ccb_h.flags |= CAM_DEV_QFRZDIS;
681    
682     memcpy(ccb.csio.cdb_io.cdb_bytes, the_cmd, the_cmd_len);
683    
684     if(cam_send_ccb(device, &ccb)<0) {
685     fprintf(stderr, "%d:%d:%d ", CurrentDevice->controller,
686     CurrentDevice->unit, CurrentDevice->lun);
687     perror("cam_send_ccb");
688     return false;
689     }
690    
691     value = ccb.ccb_h.status;
692     *stat = ccb.csio.scsi_status;
693    
694     if((value & CAM_STATUS_MASK) != CAM_REQ_CMP) {
695     char tmp[4096];
696     if((value & CAM_STATUS_MASK) == CAM_SCSI_STATUS_ERROR) {
697     scsi_sense_string(device, &ccb.csio, tmp, sizeof(tmp));
698     fprintf(stderr, "SCSI Status Error:\n%s\n", tmp);
699     return false;
700     }
701     }
702     #else /* !CAM */
703     struct scsireq* scsireq = _GetCurrentSCSIDevice();
704     if(device==NULL) return false;
705    
706     int dir_flags = 0x00;
707     if(data_length>0) dir_flags = reading?SCCMD_READ:SCCMD_WRITE;
708    
709     scsireq_reset(scsireq);
710     scsireq->timeout = (timeout?timeout:50)*1000;
711     scsireq_build(scsireq, data_length,
712     (caddr_t)buffer, dir_flags,
713     "0");
714     memcpy(scsireq->cmd, the_cmd, scsireq->cmdlen = the_cmd_len);
715    
716     int result = scsi_enter(dev->dev_fd, scsireq);
717     if(SCSIREQ_ERROR(result)) {
718     scsi_debug(stderr, result, scsireq);
719     }
720     *stat = scsireq->status;
721     #endif /* !CAM */
722    
723     if(reading) {
724     uint8* buffer_ptr = buffer;
725     for(int i=0;i<sg_size;i++) {
726     uint32 len = sg_len[i];
727     memcpy(sg_ptr[i], buffer_ptr, len);
728     #ifdef CAM
729     #ifdef VERBOSE_CAM_DEBUG
730     static char line[16];
731     for(int r=0, x=0;x<len;x++) {
732     if(x!=0&&x%16==0) { D(bug("%s\n", line)); r = 0; }
733     line[r++] = isprint(sg_ptr[i][x])?sg_ptr[i][x]:'.';
734     line[r] = 0;
735     D(bug("%02x ", sg_ptr[i][x]));
736     }
737     #endif /* VERBOSE_CAM_DEBUG */
738     #endif /* CAM */
739     buffer_ptr += len;
740     }
741     }
742     return true;
743     }