1 /* @(#)scsi-mac-iokit.c 1.17 10/05/24 Copyright 1997,2001-2010 J. Schilling */
2 #ifndef lint
3 static char __sccsid[] =
4 "@(#)scsi-mac-iokit.c 1.17 10/05/24 Copyright 1997,2001-2010 J. Schilling";
5 #endif
6 /*
7 * Interface to the Darwin IOKit SCSI drivers
8 *
9 * Notes: Uses the IOKit/scsi-commands/SCSITaskLib interface
10 *
11 * As of October 2001, this interface does not support SCSI parallel bus
12 * (old-fashioned SCSI). It does support ATAPI, Firewire, and USB.
13 *
14 * First version done by Constantine Sapuntzakis <csapuntz@Stanford.EDU>
15 *
16 * Warning: you may change this source, but if you do that
17 * you need to change the _scg_version and _scg_auth* string below.
18 * You may not return "schily" for an SCG_AUTHOR request anymore.
19 * Choose your name instead of "schily" and make clear that the version
20 * string is related to a modified source.
21 *
22 * Copyright (c) 1997,2001-2010 J. Schilling
23 */
24 /*
25 * The contents of this file are subject to the terms of the
26 * Common Development and Distribution License, Version 1.0 only
27 * (the "License"). You may not use this file except in compliance
28 * with the License.
29 *
30 * See the file CDDL.Schily.txt in this distribution for details.
31 * A copy of the CDDL is also available via the Internet at
32 * http://www.opensource.org/licenses/cddl1.txt
33 *
34 * The following exceptions apply:
35 * CDDL �3.6 needs to be replaced by: "You may create a Larger Work by
36 * combining Covered Software with other code if all other code is governed by
37 * the terms of a license that is OSI approved (see www.opensource.org) and
38 * you may distribute the Larger Work as a single product. In such a case,
39 * You must make sure the requirements of this License are fulfilled for
40 * the Covered Software."
41 *
42 * When distributing Covered Code, include this CDDL HEADER in each
43 * file and include the License file CDDL.Schily.txt from this distribution.
44 */
45
46 /*
47 * Warning: you may change this source, but if you do that
48 * you need to change the _scg_version and _scg_auth* string below.
49 * You may not return "schily" for an SCG_AUTHOR request anymore.
50 * Choose your name instead of "schily" and make clear that the version
51 * string is related to a modified source.
52 */
53 LOCAL char _scg_trans_version[] = "scsi-mac-iokit.c-1.17"; /* The version for this transport */
54
55 #define MAX_SCG 16 /* Max # of SCSI controllers */
56 #define MAX_TGT 16
57 #define MAX_LUN 8
58
59 #include <schily/stat.h>
60 #include <mach/mach.h>
61 #include <Carbon/Carbon.h>
62 #include <IOKit/IOKitLib.h>
63 #include <IOKit/IOCFPlugIn.h>
64 /*
65 * IOKit/scsi-commands/ (being a symlink at least between Panther and Leopard)
66 * did disappear on "Snow Leopard" but we do not know whether IOKit/scsi/
67 * exist before. I do not like to create an autoconf test for the file,
68 * please report if you have problems on older Mac OS X releases.
69 */
70 /*#include <IOKit/scsi-commands/SCSITaskLib.h>*/
71 #include <IOKit/scsi/SCSITaskLib.h>
72 #include <mach/mach_error.h>
73
74 struct scg_if {
75 MMCDeviceInterface **mmcDeviceInterface;
76 SCSITaskDeviceInterface **scsiTaskDeviceInterface;
77 int flags;
78 };
79
80 /*
81 * Defines for flags
82 */
83 #define NO_ACCESS 0x01
84
85 struct scg_local {
86 struct scg_if scg_if[MAX_SCG][MAX_TGT];
87 mach_port_t masterPort;
88 };
89 #define scglocal(p) ((struct scg_local *)((p)->local))
90
91 #define MAX_DMA_NEXT (32*1024)
92 #if 0
93 #define MAX_DMA_NEXT (64*1024) /* Check if this is not too big */
94 #endif
95
96 LOCAL int iokit_open __PR((SCSI *scgp, BOOL bydev, char *device, int busno, int tgt, int tlun));
97 LOCAL void iokit_warn __PR((SCSI *scgp));
98
99
100 /*
101 * Return version information for the low level SCSI transport code.
102 * This has been introduced to make it easier to trace down problems
103 * in applications.
104 */
105 LOCAL char *
scgo_version(scgp,what)106 scgo_version(scgp, what)
107 SCSI *scgp;
108 int what;
109 {
110 if (scgp != (SCSI *)0) {
111 switch (what) {
112
113 case SCG_VERSION:
114 return (_scg_trans_version);
115 /*
116 * If you changed this source, you are not allowed to
117 * return "schily" for the SCG_AUTHOR request.
118 */
119 case SCG_AUTHOR:
120 return (_scg_auth_schily);
121 case SCG_SCCS_ID:
122 return (__sccsid);
123 }
124 }
125 return ((char *)0);
126 }
127
128 LOCAL int
scgo_help(scgp,f)129 scgo_help(scgp, f)
130 SCSI *scgp;
131 FILE *f;
132 {
133 __scg_help(f, "SCSITaskDeviceInterface", "Apple SCSI",
134 "", "Mac Prom device name", "IOCompactDiscServices/0 or IODVDServices/0 or IOBDServices/0",
135 FALSE, FALSE);
136 return (0);
137 }
138
139 LOCAL char *devnames[] = {
140 "IOCompactDiscServices",
141 "IODVDServices",
142 "IOBDServices",
143 0
144 };
145 #define NDEVS ((int)(sizeof (devnames) / sizeof (devnames[0]) - 1))
146
147 /*
148 * Valid Device names:
149 * IOCompactDiscServices
150 * IODVDServices
151 * IOSCSIPeripheralDeviceNub
152 *
153 * Also a / and a number can be appended to refer to something
154 * more than the first device (e.g. IOCompactDiscServices/5 for the 5th
155 * compact disc attached)
156 */
157 LOCAL int
scgo_open(scgp,device)158 scgo_open(scgp, device)
159 SCSI *scgp;
160 char *device;
161 {
162 int busno = scg_scsibus(scgp);
163 int tgt = scg_target(scgp);
164 int tlun = scg_lun(scgp);
165 int b;
166 int t;
167 int nopen = 0;
168 int ret;
169
170 if (busno >= MAX_SCG || busno >= NDEVS || tgt >= MAX_TGT || tlun >= MAX_LUN) {
171 errno = EINVAL;
172 if (scgp->errstr) {
173 js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
174 "Illegal value for busno, target or lun '%d,%d,%d'",
175 busno, tgt, tlun);
176 }
177 return (-1);
178 }
179
180 if (scgp->local == NULL) {
181 scgp->local = malloc(sizeof (struct scg_local));
182 if (scgp->local == NULL) {
183 if (scgp->errstr)
184 js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE, "No memory for scg_local");
185 return (0);
186 }
187 for (b = 0; b < MAX_SCG; b++) {
188 for (t = 0; t < MAX_TGT; t++) {
189 scglocal(scgp)->scg_if[b][t].mmcDeviceInterface = NULL;
190 scglocal(scgp)->scg_if[b][t].scsiTaskDeviceInterface = NULL;
191 scglocal(scgp)->scg_if[b][t].flags = 0;
192 }
193 }
194 }
195
196 if ((device != NULL && *device != '\0') || (busno == -2 && tgt == -2))
197 goto openbydev;
198
199 if (busno >= 0 && tgt >= 0 && tlun >= 0) {
200 ret = iokit_open(scgp, FALSE, devnames[busno], busno, tgt, tlun);
201 if (ret == 1)
202 scg_settarget(scgp, busno, tgt, tlun);
203 else
204 scgo_close(scgp);
205 if (scgp->fd == -2)
206 iokit_warn(scgp);
207 return (ret);
208 } else {
209 int errsav = 0;
210 int exwarn = 0;
211
212 for (b = 0; b < NDEVS; b++) {
213 for (t = 0; t < MAX_TGT; t++) {
214 ret = iokit_open(scgp, FALSE, devnames[b], b, t, 0);
215 if ((scgp->debug > 0 && ret > 0) || scgp->debug > 2) {
216 js_fprintf((FILE *)scgp->errfile,
217 "b %d t %d ret %d fd %d\n",
218 b, t, ret, scgp->fd);
219 }
220 if (ret == 1)
221 nopen++;
222 if (exwarn == 0 && scgp->fd == -2) {
223 iokit_warn(scgp);
224 exwarn++;
225 }
226 }
227 }
228 seterrno(errsav);
229 }
230 openbydev:
231 if (nopen == 0) {
232 if (device == NULL || device[0] == '\0')
233 return (0);
234
235 ret = iokit_open(scgp, TRUE, device, 0, 0, 0);
236 if (ret == 1)
237 nopen++;
238 if (scgp->fd == -2)
239 iokit_warn(scgp);
240 }
241 if (nopen <= 0)
242 scgo_close(scgp);
243 return (nopen);
244 }
245
246 LOCAL void
iokit_warn(scgp)247 iokit_warn(scgp)
248 SCSI *scgp;
249 {
250 js_fprintf((FILE *)scgp->errfile, "\nWarning, 'diskarbitrationd' is running and does not allow us to\n");
251 js_fprintf((FILE *)scgp->errfile, "send SCSI commands to the drive.\n");
252 js_fprintf((FILE *)scgp->errfile, "To allow us to send SCSI commands, do the following:\n");
253 js_fprintf((FILE *)scgp->errfile, "Eject all removable media, then call as root:\n");
254 js_fprintf((FILE *)scgp->errfile, " kill -STOP `(ps -ef | grep diskarbitrationd | awk '{ print $2 }')`\n");
255 js_fprintf((FILE *)scgp->errfile, "then re-run the failed command. To continue 'diskarbitrationd' call as root:\n");
256 js_fprintf((FILE *)scgp->errfile, " kill -CONT `(ps -ef | grep diskarbitrationd | awk '{ print $2 }')`\n\n");
257 }
258
259 LOCAL int
iokit_open(scgp,bydev,device,busno,tgt,tlun)260 iokit_open(scgp, bydev, device, busno, tgt, tlun)
261 SCSI *scgp;
262 BOOL bydev;
263 char *device;
264 int busno;
265 int tgt;
266 int tlun;
267 {
268 mach_port_t masterPort = 0;
269 io_iterator_t scsiObjectIterator = 0;
270 IOReturn ioReturnValue = kIOReturnSuccess;
271 CFMutableDictionaryRef dict = NULL;
272 io_object_t scsiDevice = 0;
273 HRESULT plugInResult;
274 IOCFPlugInInterface **plugInInterface = NULL;
275 MMCDeviceInterface **mmcDeviceInterface = NULL;
276 SCSITaskDeviceInterface **scsiTaskDeviceInterface = NULL;
277 SInt32 score = 0;
278 int err = -1;
279 char *realdevice = device;
280 char *tmp;
281 int idx;
282
283 if (scgp->local == NULL)
284 return (err);
285
286 if (bydev) {
287 realdevice = tmp = strdup(device);
288 if (realdevice == NULL)
289 return (err);
290 tmp = strchr(tmp, '/');
291 if (tmp != NULL) {
292 *tmp++ = '\0';
293 tgt = atoi(tmp);
294 }
295 }
296
297 /*
298 * Get master port handle
299 * The master port handle is deallocated in scgo_close()
300 */
301 masterPort = scglocal(scgp)->masterPort;
302 if (!masterPort) {
303 ioReturnValue = IOMasterPort(bootstrap_port, &masterPort);
304
305 if (ioReturnValue != kIOReturnSuccess) {
306 js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
307 "Couldn't get a master IOKit port. Error %d",
308 ioReturnValue);
309 if (bydev)
310 free(realdevice);
311 return (err);
312 }
313 scglocal(scgp)->masterPort = masterPort;
314 }
315
316 /*
317 * Get Service dict for "IOCompactDiscServices" or "IODVDServices"
318 * or "IODBDServices"
319 */
320 dict = IOServiceMatching(realdevice);
321 if (dict == NULL) {
322 js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
323 "Couldn't create dictionary for searching '%s'.",
324 realdevice);
325 goto out;
326 }
327
328 ioReturnValue = IOServiceGetMatchingServices(masterPort, dict,
329 &scsiObjectIterator);
330 dict = NULL;
331
332 if (scsiObjectIterator == 0 ||
333 (ioReturnValue != kIOReturnSuccess)) {
334 js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
335 "No matching device %s/%d found.",
336 realdevice, tgt);
337 goto out;
338 }
339
340 for (idx = 0; (scsiDevice = IOIteratorNext(scsiObjectIterator)) != 0; idx++) {
341 if (idx == tgt)
342 break;
343 IOObjectRelease(scsiDevice);
344 scsiDevice = 0;
345 idx++;
346 }
347
348 if (scsiDevice == 0) {
349 js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
350 "No matching device %s/%d found. Iterator failed.",
351 realdevice, tgt);
352 goto out;
353 }
354
355 ioReturnValue = IOCreatePlugInInterfaceForService(scsiDevice,
356 kIOMMCDeviceUserClientTypeID,
357 kIOCFPlugInInterfaceID,
358 &plugInInterface, &score);
359 if (ioReturnValue != kIOReturnSuccess) {
360 goto try_generic;
361 }
362
363 plugInResult = (*plugInInterface)->QueryInterface(plugInInterface,
364 CFUUIDGetUUIDBytes(kIOMMCDeviceInterfaceID),
365 (LPVOID)&mmcDeviceInterface);
366
367 if (plugInResult != KERN_SUCCESS) {
368 js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
369 "Unable to get MMC Interface: 0x%lX",
370 (long)plugInResult);
371
372 goto out;
373 }
374
375 scsiTaskDeviceInterface =
376 (*mmcDeviceInterface)->GetSCSITaskDeviceInterface(mmcDeviceInterface);
377
378 if (scsiTaskDeviceInterface == NULL) {
379 js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
380 "Failed to get taskDeviceInterface");
381 goto out;
382 }
383
384 goto init;
385
386 try_generic:
387 ioReturnValue = IOCreatePlugInInterfaceForService(scsiDevice,
388 kIOSCSITaskDeviceUserClientTypeID,
389 kIOCFPlugInInterfaceID,
390 &plugInInterface, &score);
391 if (ioReturnValue != kIOReturnSuccess) {
392 js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
393 "Unable to get plugin Interface: %x",
394 ioReturnValue);
395 goto out;
396 }
397
398 plugInResult = (*plugInInterface)->QueryInterface(plugInInterface,
399 CFUUIDGetUUIDBytes(kIOSCSITaskDeviceInterfaceID),
400 (LPVOID)&scsiTaskDeviceInterface);
401
402 if (plugInResult != KERN_SUCCESS) {
403 js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
404 "Unable to get generic Interface: 0x%lX",
405 (long)plugInResult);
406
407 goto out;
408 }
409
410 init:
411 ioReturnValue =
412 (*scsiTaskDeviceInterface)->ObtainExclusiveAccess(scsiTaskDeviceInterface);
413
414 if (ioReturnValue != kIOReturnSuccess) {
415 js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
416 "Unable to get exclusive access to device");
417 scglocal(scgp)->scg_if[busno][tgt].flags |= NO_ACCESS;
418 scg_settarget(scgp, busno, tgt, tlun);
419 goto out;
420 }
421
422 if (mmcDeviceInterface) {
423 (*mmcDeviceInterface)->AddRef(mmcDeviceInterface);
424 }
425 (*scsiTaskDeviceInterface)->AddRef(scsiTaskDeviceInterface);
426 scglocal(scgp)->masterPort = masterPort;
427 scglocal(scgp)->scg_if[busno][tgt].mmcDeviceInterface = mmcDeviceInterface;
428 scglocal(scgp)->scg_if[busno][tgt].scsiTaskDeviceInterface = scsiTaskDeviceInterface;
429 scg_settarget(scgp, busno, tgt, tlun);
430 err = 1;
431
432 out:
433 if (scsiTaskDeviceInterface != NULL) {
434 (*scsiTaskDeviceInterface)->Release(scsiTaskDeviceInterface);
435 }
436
437 if (plugInInterface != NULL) {
438 (*plugInInterface)->Release(plugInInterface);
439 }
440
441 if (scsiDevice != 0) {
442 IOObjectRelease(scsiDevice);
443 }
444
445 if (scsiObjectIterator != 0) {
446 IOObjectRelease(scsiObjectIterator);
447 }
448
449 if (dict != NULL) {
450 CFRelease(dict);
451 }
452
453 if (bydev) {
454 free(realdevice);
455 }
456 return (err);
457 }
458
459 LOCAL int
scgo_close(scgp)460 scgo_close(scgp)
461 SCSI *scgp;
462 {
463 int b;
464 int t;
465 SCSITaskDeviceInterface **sc;
466 MMCDeviceInterface **mmc;
467
468 if (scgp->local == NULL)
469 return (-1);
470
471 for (b = 0; b < MAX_SCG; b++) {
472 for (t = 0; t < MAX_TGT; t++) {
473 sc = scglocal(scgp)->scg_if[b][t].scsiTaskDeviceInterface;
474 if (sc) {
475 (*sc)->ReleaseExclusiveAccess(sc);
476 (*sc)->Release(sc);
477 }
478 scglocal(scgp)->scg_if[b][t].scsiTaskDeviceInterface = NULL;
479 mmc = scglocal(scgp)->scg_if[b][t].mmcDeviceInterface;
480 if (mmc != NULL)
481 (*mmc)->Release(mmc);
482 scglocal(scgp)->scg_if[b][t].mmcDeviceInterface = NULL;
483 }
484 }
485
486 mach_port_deallocate(mach_task_self(), scglocal(scgp)->masterPort);
487
488 free(scgp->local);
489 scgp->local = NULL;
490
491 return (0);
492 }
493
494 LOCAL long
scgo_maxdma(scgp,amt)495 scgo_maxdma(scgp, amt)
496 SCSI *scgp;
497 long amt;
498 {
499 long maxdma = MAX_DMA_NEXT;
500 #ifdef SGIOCMAXDMA
501 int m;
502
503 if (ioctl(scglocal(scgp)->scgfile, SGIOCMAXDMA, &m) >= 0) {
504 maxdma = m;
505 if (scgp->debug > 0) {
506 js_fprintf((FILE *)scgp->errfile,
507 "maxdma: %d\n", maxdma);
508 }
509 }
510 #endif
511 return (maxdma);
512 }
513
514 LOCAL void *
scgo_getbuf(scgp,amt)515 scgo_getbuf(scgp, amt)
516 SCSI *scgp;
517 long amt;
518 {
519 if (scgp->debug > 0) {
520 js_fprintf((FILE *)scgp->errfile,
521 "scgo_getbuf: %ld bytes\n", amt);
522 }
523 scgp->bufbase = malloc((size_t)(amt));
524 return (scgp->bufbase);
525 }
526
527 LOCAL void
scgo_freebuf(scgp)528 scgo_freebuf(scgp)
529 SCSI *scgp;
530 {
531 if (scgp->bufbase)
532 free(scgp->bufbase);
533 scgp->bufbase = NULL;
534 }
535
536 LOCAL int
scgo_numbus(scgp)537 scgo_numbus(scgp)
538 SCSI *scgp;
539 {
540 return (MAX_SCG);
541 }
542
543 LOCAL BOOL
scgo_havebus(scgp,busno)544 scgo_havebus(scgp, busno)
545 SCSI *scgp;
546 int busno;
547 {
548 register int t;
549
550 if (scgp->local == NULL || busno < 0 || busno >= MAX_SCG)
551 return (FALSE);
552
553 for (t = 0; t < MAX_TGT; t++) {
554 if (scglocal(scgp)->scg_if[busno][t].scsiTaskDeviceInterface != NULL)
555 return (TRUE);
556 }
557 return (FALSE);
558 }
559
560 LOCAL int
scgo_fileno(scgp,busno,tgt,tlun)561 scgo_fileno(scgp, busno, tgt, tlun)
562 SCSI *scgp;
563 int busno;
564 int tgt;
565 int tlun;
566 {
567 if (scglocal(scgp) == NULL)
568 return (-1);
569
570 if (scglocal(scgp)->scg_if[busno][tgt].flags & NO_ACCESS)
571 return (-2);
572 if (scglocal(scgp)->scg_if[busno][tgt].scsiTaskDeviceInterface != NULL)
573 return (0);
574 return (-1);
575 }
576
577 LOCAL int
scgo_initiator_id(scgp)578 scgo_initiator_id(scgp)
579 SCSI *scgp;
580 {
581 return (-1);
582 }
583
584 LOCAL int
scgo_isatapi(scgp)585 scgo_isatapi(scgp)
586 SCSI *scgp;
587
588 {
589 return (FALSE);
590 }
591
592 LOCAL int
scgo_reset(scgp,what)593 scgo_reset(scgp, what)
594 SCSI *scgp;
595 int what;
596 {
597 if (what == SCG_RESET_NOP)
598 return (0);
599 if (what != SCG_RESET_BUS) {
600 errno = EINVAL;
601 return (-1);
602 }
603
604 errno = 0;
605 return (-1);
606 }
607
608 LOCAL int
scgo_send(scgp)609 scgo_send(scgp)
610 SCSI *scgp;
611 {
612 struct scg_cmd *sp = scgp->scmd;
613 SCSITaskDeviceInterface **sc = NULL;
614 SCSITaskInterface **cmd = NULL;
615 #if defined(__LP64__) /* Ugly differences for LP64 */
616 IOAddressRange iov;
617 #else
618 IOVirtualRange iov;
619 #endif
620 SCSI_Sense_Data senseData;
621 SCSITaskStatus status;
622 UInt64 bytesTransferred;
623 IOReturn ioReturnValue;
624 int ret = 0;
625
626 if (scgp->local == NULL) {
627 sp->error = SCG_FATAL;
628 return (0);
629 }
630 sc = scglocal(scgp)->scg_if[scg_scsibus(scgp)][scg_target(scgp)].scsiTaskDeviceInterface;
631 if (sc == NULL) {
632 sp->error = SCG_FATAL;
633 return (0);
634 }
635
636 cmd = (*sc)->CreateSCSITask(sc);
637 if (cmd == NULL) {
638 js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
639 "Failed to create SCSI task");
640 ret = -1;
641
642 sp->error = SCG_FATAL;
643 sp->ux_errno = EIO;
644 goto out;
645 }
646
647
648 #if defined(__LP64__) /* Ugly differences for LP64 */
649 iov.address = (mach_vm_address_t) sp->addr;
650 #else
651 iov.address = (IOVirtualAddress) sp->addr;
652 #endif
653 iov.length = sp->size;
654
655 ioReturnValue = (*cmd)->SetCommandDescriptorBlock(cmd,
656 sp->cdb.cmd_cdb, sp->cdb_len);
657
658 if (ioReturnValue != kIOReturnSuccess) {
659 js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
660 "SetCommandDescriptorBlock failed with status %x",
661 ioReturnValue);
662 ret = -1;
663 goto out;
664 }
665
666 ioReturnValue = (*cmd)->SetScatterGatherEntries(cmd, &iov, 1, sp->size,
667 (sp->flags & SCG_RECV_DATA) ?
668 kSCSIDataTransfer_FromTargetToInitiator :
669 kSCSIDataTransfer_FromInitiatorToTarget);
670 if (ioReturnValue != kIOReturnSuccess) {
671 js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
672 "SetScatterGatherEntries failed with status %x",
673 ioReturnValue);
674 ret = -1;
675 goto out;
676 }
677
678 ioReturnValue = (*cmd)->SetTimeoutDuration(cmd, sp->timeout * 1000);
679 if (ioReturnValue != kIOReturnSuccess) {
680 js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
681 "SetTimeoutDuration failed with status %x",
682 ioReturnValue);
683 ret = -1;
684 goto out;
685 }
686
687 memset(&senseData, 0, sizeof (senseData));
688
689 seterrno(0);
690 ioReturnValue = (*cmd)->ExecuteTaskSync(cmd,
691 &senseData, &status, &bytesTransferred);
692
693 sp->resid = sp->size - bytesTransferred;
694 sp->error = SCG_NO_ERROR;
695 sp->ux_errno = geterrno();
696
697 if (ioReturnValue != kIOReturnSuccess) {
698 js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
699 "Command execution failed with status %x",
700 ioReturnValue);
701 sp->error = SCG_RETRYABLE;
702 ret = -1;
703 goto out;
704 }
705
706 memset(&sp->scb, 0, sizeof (sp->scb));
707 memset(&sp->u_sense.cmd_sense, 0, sizeof (sp->u_sense.cmd_sense));
708 if (senseData.VALID_RESPONSE_CODE != 0 || status == 0x02) {
709 /*
710 * There is no sense length - we need to asume that
711 * we always get 18 bytes.
712 */
713 sp->sense_count = kSenseDefaultSize;
714 memmove(&sp->u_sense.cmd_sense, &senseData, kSenseDefaultSize);
715 if (sp->ux_errno == 0)
716 sp->ux_errno = EIO;
717 }
718
719 sp->u_scb.cmd_scb[0] = status;
720
721 /* ??? */
722 if (status == kSCSITaskStatus_No_Status) {
723 sp->error = SCG_RETRYABLE;
724 ret = -1;
725 goto out;
726 }
727 /*
728 * XXX Is it possible to have other senseful SCSI transport error codes?
729 */
730
731 out:
732 if (cmd != NULL) {
733 (*cmd)->Release(cmd);
734 }
735
736 return (ret);
737 }
738