ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/FreeBSD/scsi_freebsd.cpp
Revision: 1.7
Committed: 2008-01-01T09:40:33Z (16 years, 4 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 * scsi_freebsd.cpp - SCSI Manager, FreeBSD SCSI Driver implementation
3 * Copyright (C) 1999 Orlando Bassotto
4 *
5 * Basilisk II (C) 1997-2008 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 }