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 |
} |