|
|
1.1 ! root 1: /* @(#)scsi-linux-sg.c 1.30 98/11/06 Copyright 1997 J. Schilling */ ! 2: #ifndef lint ! 3: static char __sccsid[] = ! 4: "@(#)scsi-linux-sg.c 1.30 98/11/06 Copyright 1997 J. Schilling"; ! 5: #endif ! 6: /* ! 7: * Interface for Linux generic SCSI implementation (sg). ! 8: * ! 9: * This is the interface for the broken Linux SCSI generic driver. ! 10: * This is a hack, that tries to emulate the functionality ! 11: * of the scg driver. ! 12: * ! 13: * Design flaws of the sg driver: ! 14: * - cannot see if SCSI command could not be send ! 15: * - cannot get SCSI status byte ! 16: * - cannot get real dma count of tranfer ! 17: * - cannot get number of bytes valid in auto sense data ! 18: * - to few data in auto sense (CCS/SCSI-2/SCSI-3 needs >= 18) ! 19: * ! 20: * This code contains support for the sg driver version 2 ! 21: * ! 22: * Copyright (c) 1997 J. Schilling ! 23: */ ! 24: /* ! 25: * This program is free software; you can redistribute it and/or modify ! 26: * it under the terms of the GNU General Public License as published by ! 27: * the Free Software Foundation; either version 2, or (at your option) ! 28: * any later version. ! 29: * ! 30: * This program is distributed in the hope that it will be useful, ! 31: * but WITHOUT ANY WARRANTY; without even the implied warranty of ! 32: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 33: * GNU General Public License for more details. ! 34: * ! 35: * You should have received a copy of the GNU General Public License ! 36: * along with this program; see the file COPYING. If not, write to ! 37: * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. ! 38: */ ! 39: ! 40: #include <linux/version.h> ! 41: ! 42: #define DEBUG ! 43: ! 44: #ifndef LINUX_VERSION_CODE /* Very old kernel? */ ! 45: # define LINUX_VERSION_CODE 0 ! 46: #endif ! 47: ! 48: #if LINUX_VERSION_CODE >= 0x01031a /* <linux/scsi.h> introduced in 1.3.26 */ ! 49: #if LINUX_VERSION_CODE >= 0x020000 /* <scsi/scsi.h> introduced somewhere. */ ! 50: /* Need to fine tune the ifdef so we get the transition point right. */ ! 51: #include <scsi/scsi.h> ! 52: #else ! 53: #include <linux/scsi.h> ! 54: #endif ! 55: #else ! 56: #define __KERNEL__ ! 57: #include <linux/fs.h> ! 58: #undef __KERNEL__ ! 59: #include "block/blk.h" ! 60: #include "scsi/scsi.h" ! 61: #endif ! 62: ! 63: #include <stdlib.h> ! 64: #include <stdio.h> ! 65: #include <errno.h> ! 66: #include <unistd.h> ! 67: #include <sys/types.h> ! 68: #include <sys/stat.h> ! 69: #include <sys/ioctl.h> ! 70: #include <sys/time.h> ! 71: #include <fcntl.h> ! 72: #include <scsi/sg.h> ! 73: #include <asm/param.h> ! 74: ! 75: #include "scg/defs.h" ! 76: #include "scg/scsitransp.h" ! 77: #include "scg/scgcmd.h" ! 78: ! 79: #ifndef SCSI_IOCTL_GET_BUS_NUMBER ! 80: #define SCSI_IOCTL_GET_BUS_NUMBER 0x5386 ! 81: #endif ! 82: ! 83: /* ! 84: * XXX There must be a better way than duplicating things from system include ! 85: * XXX files. This is stolen from /usr/src/linux/drivers/scsi/scsi.h ! 86: */ ! 87: #ifndef DID_OK ! 88: #define DID_OK 0x00 /* NO error */ ! 89: #define DID_NO_CONNECT 0x01 /* Couldn't connect before timeout period */ ! 90: #define DID_BUS_BUSY 0x02 /* BUS stayed busy through time out period */ ! 91: #define DID_TIME_OUT 0x03 /* TIMED OUT for other reason */ ! 92: #define DID_BAD_TARGET 0x04 /* BAD target. */ ! 93: #define DID_ABORT 0x05 /* Told to abort for some other reason */ ! 94: #define DID_PARITY 0x06 /* Parity error */ ! 95: #define DID_ERROR 0x07 /* Internal error */ ! 96: #define DID_RESET 0x08 /* Reset by somebody. */ ! 97: #define DID_BAD_INTR 0x09 /* Got an interrupt we weren't expecting. */ ! 98: #endif ! 99: ! 100: #define MAX_SCG 4 /* Max # of SCSI controllers */ ! 101: #define MAX_TGT 16 ! 102: #define MAX_LUN 8 ! 103: ! 104: typedef struct SCSIPrivate { ! 105: int scgfile; /* Used for SG_GET_BUFSIZE ioctl() */ ! 106: short scgfiles[MAX_SCG][MAX_TGT][MAX_LUN]; ! 107: short buscookies[MAX_SCG]; ! 108: int pack_id; /* Should be a random number */ ! 109: char *SCSIbuf; ! 110: long scg_maxdma; ! 111: } SCSIPrivate; ! 112: ! 113: #ifdef SG_BIG_BUFF ! 114: #define MAX_DMA_LINUX SG_BIG_BUFF /* Defined in include/scsi/sg.h */ ! 115: #else ! 116: #define MAX_DMA_LINUX (4*1024) /* Old Linux versions */ ! 117: #endif ! 118: ! 119: #ifndef SG_MAX_SENSE ! 120: # define SG_MAX_SENSE 16 /* Too small for CCS / SCSI-2 */ ! 121: #endif /* But cannot be changed */ ! 122: ! 123: ! 124: #if !defined(__i386) && !defined(i386) && !defined(mc68000) ! 125: #define MISALIGN ! 126: #endif ! 127: /*#define MISALIGN*/ ! 128: /*#undef SG_GET_BUFSIZE*/ ! 129: ! 130: #if defined(USE_PG) && !defined(USE_PG_ONLY) ! 131: #include "scsi-linux-pg.c" ! 132: #endif ! 133: ! 134: #ifdef MISALIGN ! 135: LOCAL int scsi_getint __PR((int *ip)); ! 136: #endif ! 137: LOCAL int scsi_send __PR((SCSI *scgp, int f, struct scg_cmd *sp)); ! 138: LOCAL BOOL sg_setup __PR((SCSI *scgp, int f, int busno, int tgt, int tlun)); ! 139: LOCAL void sg_initdev __PR((SCSI *scgp, int f)); ! 140: LOCAL int sg_mapbus __PR((SCSI *scgp, int ino)); ! 141: LOCAL BOOL sg_mapdev __PR((SCSI *scgp, int f, int *busp, int *tgtp, int *lunp, ! 142: int *chanp, int *inop)); ! 143: LOCAL void sg_settimeout __PR((int f, int timeout)); ! 144: LOCAL long scsi_maxdma __PR((SCSI *scgp)); ! 145: LOCAL void scsitimes __PR((SCSI *scgp)); ! 146: ! 147: EXPORT ! 148: int scsi_open(scgp, device, busno, tgt, tlun) ! 149: SCSI *scgp; ! 150: char *device; ! 151: int busno; ! 152: int tgt; ! 153: int tlun; ! 154: { ! 155: register int f; ! 156: register int i; ! 157: register int b; ! 158: register int t; ! 159: register int l; ! 160: register int nopen = 0; ! 161: char devname[64]; ! 162: ! 163: if (!(scgp->private = calloc(1, sizeof(*scgp->private)))) { ! 164: return -1; ! 165: } ! 166: scgp->private->pack_id = rand(); /* now is a random number */ ! 167: scgp->private->scgfile = -1; ! 168: scgp->private->SCSIbuf = (void *)-1; ! 169: ! 170: for (b=0; b < MAX_SCG; b++) { ! 171: scgp->private->buscookies[b] = (short)-1; ! 172: for (t=0; t < MAX_TGT; t++) { ! 173: for (l=0; l < MAX_LUN ; l++) ! 174: scgp->private->scgfiles[b][t][l] = (short)-1; ! 175: } ! 176: } ! 177: if ((device != NULL && *device != '\0') || (busno == -2 && tgt == -2)) ! 178: goto openbydev; ! 179: ! 180: if (busno >= 0 && tgt >= 0 && tlun >= 0) { ! 181: if (busno >= MAX_SCG || tgt >= MAX_TGT || tlun >= MAX_LUN) ! 182: return (-1); ! 183: } ! 184: ! 185: for (i=0; i < 32; i++) { ! 186: sprintf(devname, "/dev/sg%d", i); ! 187: f = open(devname, 2); ! 188: if (f < 0) { ! 189: if (errno != ENOENT && errno != ENXIO && errno != ENODEV) ! 190: fprintf(stderr, "Cannot open '%s'.\n", devname); ! 191: } else { ! 192: if (sg_setup(scgp, f, busno, tgt, tlun)) ! 193: return (++nopen); ! 194: if (busno < 0 && tgt < 0 && tlun < 0) ! 195: nopen++; ! 196: } ! 197: } ! 198: if (nopen == 0) for (i=0; i <= 25; i++) { ! 199: sprintf(devname, "/dev/sg%c", i+'a'); ! 200: f = open(devname, 2); ! 201: if (f < 0) { ! 202: if (errno != ENOENT && errno != ENXIO && errno != ENODEV) ! 203: fprintf(stderr, "Cannot open '%s'.\n", devname); ! 204: } else { ! 205: if (sg_setup(scgp, f, busno, tgt, tlun)) ! 206: return (++nopen); ! 207: if (busno < 0 && tgt < 0 && tlun < 0) ! 208: nopen++; ! 209: } ! 210: } ! 211: openbydev: ! 212: if (device != NULL && *device != '\0') { ! 213: f = open(device, 2); ! 214: if (f < 0 && errno == ENOENT) ! 215: goto openpg; ! 216: ! 217: if (!sg_mapdev(scgp, f, &busno, &tgt, &tlun, 0, 0)) { ! 218: close(f); ! 219: goto openpg; ! 220: } ! 221: ! 222: if (scgp->scsibus < 0) ! 223: scgp->scsibus = busno; ! 224: if (scgp->target < 0) ! 225: scgp->target = tgt; ! 226: if (scgp->lun < 0) ! 227: scgp->lun = tlun; ! 228: ! 229: if (sg_setup(scgp, f, busno, tgt, tlun)) ! 230: return (++nopen); ! 231: } ! 232: openpg: ! 233: #ifdef USE_PG ! 234: nopen += pg_open(scgp, device, busno, tgt, tlun); ! 235: #endif ! 236: return (nopen); ! 237: } ! 238: ! 239: LOCAL BOOL ! 240: sg_setup(scgp, f, busno, tgt, tlun) ! 241: SCSI *scgp; ! 242: int f; ! 243: int busno; ! 244: int tgt; ! 245: int tlun; ! 246: { ! 247: int n; ! 248: int Chan; ! 249: int Ino; ! 250: int Bus; ! 251: int Target; ! 252: int Lun; ! 253: BOOL onetarget = FALSE; ! 254: ! 255: ! 256: if (scgp->scsibus >= 0 && scgp->target >= 0 && scgp->lun >= 0) ! 257: onetarget = TRUE; ! 258: ! 259: sg_mapdev(scgp, f, &Bus, &Target, &Lun, &Chan, &Ino); ! 260: ! 261: /* ! 262: * For old kernels try to make the best guess. ! 263: */ ! 264: Ino |= Chan << 8; ! 265: n = sg_mapbus(scgp, Ino); ! 266: if (Bus == -1) { ! 267: Bus = n; ! 268: if (scgp->debug) ! 269: printf("SCSI Bus: %d (mapped from %d)\n", Bus, Ino); ! 270: } ! 271: ! 272: /* if (scgp->private->scgfiles[Bus][Target][Lun] == (short)-1) */ ! 273: scgp->private->scgfiles[Bus][Target][Lun] = (short)f; ! 274: ! 275: if (onetarget) { ! 276: if (Bus == busno && Target == tgt && Lun == tlun) { ! 277: sg_initdev(scgp, f); ! 278: scgp->private->scgfile = f; /* remember file for ioctl's */ ! 279: return (TRUE); ! 280: } else { ! 281: scgp->private->scgfiles[Bus][Target][Lun] = (short)-1; ! 282: close(f); ! 283: } ! 284: } else { ! 285: sg_initdev(scgp, f); ! 286: if (scgp->private->scgfile < 0) ! 287: scgp->private->scgfile = f; /* remember file for ioctl's */ ! 288: } ! 289: return (FALSE); ! 290: } ! 291: ! 292: LOCAL void ! 293: sg_initdev(scgp, f) ! 294: SCSI *scgp; ! 295: int f; ! 296: { ! 297: struct sg_rep { ! 298: struct sg_header hd; ! 299: unsigned char rbuf[100]; ! 300: } sg_rep; ! 301: int n; ! 302: ! 303: /* Eat any unwanted garbage from prior use of this device */ ! 304: ! 305: n = fcntl(f, F_GETFL); /* Be very proper about this */ ! 306: fcntl(f, F_SETFL, n|O_NONBLOCK); ! 307: ! 308: fillbytes((caddr_t)&sg_rep, sizeof(struct sg_header), '\0'); ! 309: sg_rep.hd.reply_len = sizeof(struct sg_header); ! 310: ! 311: while (read(f, &sg_rep, sizeof(sg_rep)) >= 0 || errno != EAGAIN) ! 312: ; ! 313: ! 314: fcntl(f, F_SETFL, n); ! 315: ! 316: sg_settimeout(f, scgp->deftimeout); ! 317: } ! 318: ! 319: LOCAL int ! 320: sg_mapbus(scgp, ino) ! 321: SCSI *scgp; ! 322: int ino; ! 323: { ! 324: register int i; ! 325: ! 326: for (i=0; i < MAX_SCG; i++) { ! 327: if (scgp->private->buscookies[i] == (short)-1) { ! 328: scgp->private->buscookies[i] = ino; ! 329: return (i); ! 330: } ! 331: ! 332: if (scgp->private->buscookies[i] == ino) ! 333: return (i); ! 334: } ! 335: return (0); ! 336: } ! 337: ! 338: LOCAL BOOL ! 339: sg_mapdev(scgp, f, busp, tgtp, lunp, chanp, inop) ! 340: SCSI *scgp; ! 341: int f; ! 342: int *busp; ! 343: int *tgtp; ! 344: int *lunp; ! 345: int *chanp; ! 346: int *inop; ! 347: { ! 348: struct sg_id { ! 349: long l1; /* target | lun << 8 | channel << 16 | low_ino << 24 */ ! 350: long l2; /* Unique id */ ! 351: } sg_id; ! 352: int Chan; ! 353: int Ino; ! 354: int Bus; ! 355: int Target; ! 356: int Lun; ! 357: ! 358: if (ioctl(f, SCSI_IOCTL_GET_IDLUN, &sg_id)) ! 359: return (FALSE); ! 360: if (scgp->debug) ! 361: printf("l1: 0x%lX l2: 0x%lX\n", sg_id.l1, sg_id.l2); ! 362: if (ioctl(f, SCSI_IOCTL_GET_BUS_NUMBER, &Bus) < 0) { ! 363: Bus = -1; ! 364: } ! 365: ! 366: Target = sg_id.l1 & 0xFF; ! 367: Lun = (sg_id.l1 >> 8) & 0xFF; ! 368: Chan = (sg_id.l1 >> 16) & 0xFF; ! 369: Ino = (sg_id.l1 >> 24) & 0xFF; ! 370: if (scgp->debug) { ! 371: printf("Bus: %d Target: %d Lun: %d Chan: %d Ino: %d\n", ! 372: Bus, Target, Lun, Chan, Ino); ! 373: } ! 374: *busp = Bus; ! 375: *tgtp = Target; ! 376: *lunp = Lun; ! 377: if (chanp) ! 378: *chanp = Chan; ! 379: if (inop) ! 380: *inop = Ino; ! 381: return (TRUE); ! 382: } ! 383: ! 384: LOCAL long ! 385: scsi_maxdma(scgp) ! 386: SCSI *scgp; ! 387: { ! 388: long maxdma = MAX_DMA_LINUX; ! 389: ! 390: #ifdef SG_GET_BUFSIZE ! 391: /* ! 392: * We assume that all /dev/sg instances use the same ! 393: * maximum buffer size. ! 394: */ ! 395: if ((maxdma = ioctl(scgp->private->scgfile, SG_GET_BUFSIZE, 0)) < 0) { ! 396: if (scgp->private->scgfile >= 0) { ! 397: maxdma = MAX_DMA_LINUX; ! 398: } ! 399: } ! 400: #endif ! 401: #ifdef USE_PG ! 402: if (scgp->scsibus == pgbus) ! 403: return (pg_maxdma(scgp)); ! 404: if ((scgp->scsibus < 0) && (pg_maxdma(scgp) < maxdma)) ! 405: return (pg_maxdma(scgp)); ! 406: #endif ! 407: return (maxdma); ! 408: } ! 409: ! 410: EXPORT void * ! 411: scsi_getbuf(scgp, amt) ! 412: SCSI *scgp; ! 413: long amt; ! 414: { ! 415: char *ret; ! 416: ! 417: if (scgp->private->scg_maxdma == 0) ! 418: scgp->private->scg_maxdma = scsi_maxdma(scgp); ! 419: ! 420: if (amt <= 0 || amt > scgp->private->scg_maxdma) ! 421: return ((void *)0); ! 422: if (scgp->debug) ! 423: printf("scsi_getbuf: %ld bytes\n", amt); ! 424: /* ! 425: * For performance reason, we allocate pagesize() ! 426: * bytes before the SCSI buffer to avoid ! 427: * copying the whole buffer contents when ! 428: * setting up the /dev/sg data structures. ! 429: */ ! 430: ret = valloc((size_t)(amt+getpagesize())); ! 431: if (ret == NULL) ! 432: return (ret); ! 433: ret += getpagesize(); ! 434: scgp->private->SCSIbuf = ret; ! 435: return ((void *)ret); ! 436: } ! 437: ! 438: EXPORT ! 439: BOOL scsi_havebus(scgp, busno) ! 440: SCSI *scgp; ! 441: int busno; ! 442: { ! 443: register int t; ! 444: register int l; ! 445: ! 446: if (busno < 0 || busno >= MAX_SCG) ! 447: return (FALSE); ! 448: ! 449: for (t=0; t < MAX_TGT; t++) { ! 450: for (l=0; l < MAX_LUN ; l++) ! 451: if (scgp->private->scgfiles[busno][t][l] >= 0) ! 452: return (TRUE); ! 453: } ! 454: return (FALSE); ! 455: } ! 456: ! 457: EXPORT ! 458: int scsi_fileno(scgp, busno, tgt, tlun) ! 459: SCSI *scgp; ! 460: int busno; ! 461: int tgt; ! 462: int tlun; ! 463: { ! 464: if (busno < 0 || busno >= MAX_SCG || ! 465: tgt < 0 || tgt >= MAX_TGT || ! 466: tlun < 0 || tlun >= MAX_LUN) ! 467: return (-1); ! 468: ! 469: return ((int)scgp->private->scgfiles[busno][tgt][tlun]); ! 470: } ! 471: ! 472: EXPORT ! 473: int scsi_isatapi(scgp) ! 474: SCSI *scgp; ! 475: { ! 476: #ifdef USE_PG ! 477: if (scgp->scsibus == pgbus) ! 478: return (pg_isatapi(scgp)); ! 479: #endif ! 480: ! 481: #ifdef SG_EMULATED_HOST ! 482: { ! 483: int emulated = FALSE; ! 484: int f = scsi_fileno(scgp, scgp->scsibus, scgp->target, scgp->lun); ! 485: ! 486: if (ioctl(f, SG_EMULATED_HOST, &emulated) >= 0) ! 487: return (emulated != 0); ! 488: } ! 489: #endif ! 490: return (-1); ! 491: } ! 492: ! 493: EXPORT ! 494: int scsireset(scgp) ! 495: SCSI *scgp; ! 496: { ! 497: #ifdef USE_PG ! 498: if (scgp->scsibus == pgbus) ! 499: return (pg_reset(scgp)); ! 500: #endif ! 501: /* ! 502: * Do we have a SCSI reset in the Linux sg driver? ! 503: */ ! 504: return (-1); ! 505: } ! 506: ! 507: LOCAL void ! 508: sg_settimeout(f, tmo) ! 509: int f; ! 510: int tmo; ! 511: { ! 512: tmo *= HZ; ! 513: if (tmo) ! 514: tmo += HZ/2; ! 515: ! 516: if (ioctl(f, SG_SET_TIMEOUT, &tmo) < 0) ! 517: fprintf(stderr, "Cannot set SG_SET_TIMEOUT.\n"); ! 518: } ! 519: ! 520: /* ! 521: * Get misaligned int. ! 522: * Needed for all recent processors (sparc/ppc/alpha) ! 523: * because the /dev/sg design forces us to do misaligned ! 524: * reads of integers. ! 525: */ ! 526: #ifdef MISALIGN ! 527: LOCAL int ! 528: scsi_getint(ip) ! 529: int *ip; ! 530: { ! 531: int ret; ! 532: register char *cp = (char *)ip; ! 533: register char *tp = (char *)&ret; ! 534: register int i; ! 535: ! 536: for (i = sizeof(int); --i >= 0; ) ! 537: *tp++ = *cp++; ! 538: ! 539: return (ret); ! 540: } ! 541: #define GETINT(a) scsi_getint(&(a)) ! 542: #else ! 543: #define GETINT(a) (a) ! 544: #endif ! 545: ! 546: LOCAL int ! 547: scsi_send(scgp, f, sp) ! 548: SCSI *scgp; ! 549: int f; ! 550: struct scg_cmd *sp; ! 551: { ! 552: struct sg_rq *sgp; ! 553: struct sg_rq *sgp2; ! 554: int i; ! 555: int pack_len; ! 556: int reply_len; ! 557: int amt = sp->cdb_len; ! 558: struct sg_rq { ! 559: struct sg_header hd; ! 560: unsigned char buf[MAX_DMA_LINUX+SCG_MAX_CMD]; ! 561: } sg_rq; ! 562: #ifdef SG_GET_BUFSIZE /* We may use a 'sg' version 2 driver */ ! 563: char driver_byte; ! 564: char host_byte; ! 565: char msg_byte; ! 566: char status_byte; ! 567: #endif ! 568: ! 569: if (f < 0) { ! 570: sp->error = SCG_FATAL; ! 571: return (0); ! 572: } ! 573: #ifdef USE_PG ! 574: if (scgp->scsibus == pgbus) ! 575: return (pg_send(scgp, f, sp)); ! 576: #endif ! 577: if (sp->timeout != scgp->deftimeout) ! 578: sg_settimeout(f, sp->timeout); ! 579: ! 580: ! 581: sgp2 = sgp = &sg_rq; ! 582: if (sp->addr == scgp->private->SCSIbuf) { ! 583: sgp = (struct sg_rq *) ! 584: (scgp->private->SCSIbuf - (sizeof(struct sg_header) + amt)); ! 585: sgp2 = (struct sg_rq *) ! 586: (scgp->private->SCSIbuf - (sizeof(struct sg_header))); ! 587: } else { ! 588: if (scgp->debug) { ! 589: printf("DMA addr: 0x%8.8lX size: %d - using copy buffer\n", ! 590: (long)sp->addr, sp->size); ! 591: } ! 592: if (sp->size > (int)(sizeof(sg_rq.buf) - SCG_MAX_CMD)) { ! 593: errno = ENOMEM; ! 594: return (-1); ! 595: } ! 596: } ! 597: ! 598: /* ! 599: * This is done to avoid misaligned access of sgp->some_int ! 600: */ ! 601: pack_len = sizeof(struct sg_header) + amt; ! 602: reply_len = sizeof(struct sg_header); ! 603: if (sp->flags & SCG_RECV_DATA) { ! 604: reply_len += sp->size; ! 605: } else { ! 606: pack_len += sp->size; ! 607: } ! 608: ! 609: #ifdef MISALIGN ! 610: /* ! 611: * sgp->some_int may be misaligned if (sp->addr == SCSIbuf) ! 612: * This is no problem on Intel porocessors, however ! 613: * all other processors don't like it. ! 614: * sizeof(struct sg_header) + amt is usually not a multiple of ! 615: * sizeof(int). For this reason, we fill in the values into sg_rq ! 616: * which is always corectly aligned and then copy it to the real ! 617: * location if this location differs from sg_rq. ! 618: * Never read/write directly to sgp->some_int !!!!! ! 619: */ ! 620: fillbytes((caddr_t)&sg_rq, sizeof(struct sg_header), '\0'); ! 621: ! 622: sg_rq.hd.pack_len = pack_len; ! 623: sg_rq.hd.reply_len = reply_len; ! 624: sg_rq.hd.pack_id = scgp->private->pack_id++; ! 625: /* sg_rq.hd.result = 0; not needed because of fillbytes() */ ! 626: ! 627: if ((caddr_t)&sg_rq != (caddr_t)sgp) ! 628: movebytes((caddr_t)&sg_rq, (caddr_t)sgp, sizeof(struct sg_header)); ! 629: #else ! 630: fillbytes((caddr_t)sgp, sizeof(struct sg_header), '\0'); ! 631: ! 632: sgp->hd.pack_len = pack_len; ! 633: sgp->hd.reply_len = reply_len; ! 634: sgp->hd.pack_id = scgp->private->pack_id++; ! 635: /* sgp->hd.result = 0; not needed because of fillbytes() */ ! 636: #endif ! 637: if (amt == 12) ! 638: sgp->hd.twelve_byte = 1; ! 639: ! 640: ! 641: for (i = 0; i < amt; i++ ) { ! 642: sgp->buf[i] = sp->cdb.cmd_cdb[i];; ! 643: } ! 644: if (!(sp->flags & SCG_RECV_DATA)) { ! 645: if ((void *)sp->addr != (void *)&sgp->buf[amt]) ! 646: movebytes(sp->addr, &sgp->buf[amt], sp->size); ! 647: amt += sp->size; ! 648: } ! 649: #ifdef SG_GET_BUFSIZE ! 650: sgp->hd.want_new = 1; /* Order new behaviour */ ! 651: sgp->hd.cdb_len = sp->cdb_len; /* Set CDB length */ ! 652: if (sp->sense_len > SG_MAX_SENSE) ! 653: sgp->hd.sense_len = SG_MAX_SENSE; ! 654: else ! 655: sgp->hd.sense_len = sp->sense_len; ! 656: #endif ! 657: i = sizeof(struct sg_header) + amt; ! 658: if ((amt = write(f, sgp, i)) < 0) { /* write */ ! 659: sg_settimeout(f, scgp->deftimeout); ! 660: return (-1); ! 661: } else if (amt != i) { ! 662: /* errmsg("scsi_send(%s) wrote %d bytes (expected %d).\n", ! 663: scsi_command, amt, i);*/ ! 664: } ! 665: ! 666: if (sp->addr == scgp->private->SCSIbuf) { ! 667: movebytes(sgp, sgp2, sizeof(struct sg_header)); ! 668: sgp = sgp2; ! 669: } ! 670: sgp->hd.sense_buffer[0] = 0; ! 671: if ((amt = read(f, sgp, reply_len)) < 0) { /* read */ ! 672: sg_settimeout(f, scgp->deftimeout); ! 673: return (-1); ! 674: } ! 675: ! 676: if (sp->flags & SCG_RECV_DATA && ((void *)sgp->buf != (void *)sp->addr)) { ! 677: movebytes(sgp->buf, sp->addr, sp->size); ! 678: } ! 679: sp->ux_errno = GETINT(sgp->hd.result); /* Unaligned read */ ! 680: sp->error = SCG_NO_ERROR; ! 681: ! 682: #ifdef SG_GET_BUFSIZE ! 683: if (sgp->hd.grant_new) { ! 684: sp->sense_count = sgp->hd.sense_len; ! 685: pack_len = GETINT(sgp->hd.sg_cmd_status); /* Unaligned read */ ! 686: driver_byte = (pack_len >> 24) & 0xFF; ! 687: host_byte = (pack_len >> 16) & 0xFF; ! 688: msg_byte = (pack_len >> 8) & 0xFF; ! 689: status_byte = pack_len & 0xFF; ! 690: ! 691: switch (host_byte) { ! 692: ! 693: case DID_OK: ! 694: if (sgp->hd.sense_buffer[0] != 0) { ! 695: /* ! 696: * The Linux SCSI system up to 2.1.xx ! 697: * trashes the status byte in the ! 698: * kernel. Until this gets fixed, we ! 699: * need this hack. ! 700: */ ! 701: sp->error = SCG_RETRYABLE; ! 702: status_byte = 2; ! 703: sgp->hd.sense_len = SG_MAX_SENSE; ! 704: } ! 705: break; ! 706: ! 707: case DID_NO_CONNECT: /* Arbitration won, retry NO_CONNECT? */ ! 708: case DID_BAD_TARGET: ! 709: sp->error = SCG_FATAL; ! 710: break; ! 711: ! 712: case DID_TIME_OUT: ! 713: sp->error = SCG_TIMEOUT; ! 714: break; ! 715: ! 716: default: ! 717: sp->error = SCG_RETRYABLE; ! 718: break; ! 719: ! 720: } ! 721: if ((host_byte != DID_OK || status_byte != 0) && sp->ux_errno == 0) ! 722: sp->ux_errno = EIO; ! 723: sp->u_scb.cmd_scb[0] = status_byte; ! 724: if (status_byte & 2) { ! 725: sp->sense_count = sgp->hd.sense_len; ! 726: movebytes(sgp->hd.sense_buffer, sp->u_sense.cmd_sense, sp->sense_count); ! 727: } ! 728: } else ! 729: #endif ! 730: { ! 731: if (GETINT(sgp->hd.result) == EBUSY) { /* Unaligned read */ ! 732: struct timeval to; ! 733: ! 734: to.tv_sec = sp->timeout; ! 735: to.tv_usec = 500000; ! 736: scsitimes(scgp); ! 737: ! 738: if (scgp->cmdstop->tv_sec < to.tv_sec || ! 739: (scgp->cmdstop->tv_sec == to.tv_sec && ! 740: scgp->cmdstop->tv_usec < to.tv_usec)) { ! 741: ! 742: sp->ux_errno = 0; ! 743: sp->error = SCG_TIMEOUT; /* a timeout */ ! 744: } else { ! 745: sp->error = SCG_RETRYABLE; /* may be BUS_BUSY */ ! 746: } ! 747: } ! 748: ! 749: if (sp->flags & SCG_RECV_DATA) ! 750: sp->resid = (sp->size + sizeof(struct sg_header)) - amt; ! 751: else ! 752: sp->resid = 0; /* sg version1 cannot return DMA resid count */ ! 753: ! 754: if (sgp->hd.sense_buffer[0] != 0) { ! 755: sp->error = SCG_RETRYABLE; ! 756: sp->scb.chk = 1; ! 757: sp->sense_count = SG_MAX_SENSE; ! 758: movebytes(sgp->hd.sense_buffer, sp->u_sense.cmd_sense, sp->sense_count); ! 759: if (sp->ux_errno == 0) ! 760: sp->ux_errno = EIO; ! 761: } ! 762: } ! 763: ! 764: if (scgp->verbose > 0 && scgp->debug) { ! 765: #ifdef SG_GET_BUFSIZE ! 766: printf("status: %X pack_len: %d, reply_len: %d pack_id: %d result: %d wn: %d gn: %d cdb_len: %d sense_len: %d sense[0]: %02X\n", ! 767: GETINT(sgp->hd.sg_cmd_status), ! 768: GETINT(sgp->hd.pack_len), ! 769: GETINT(sgp->hd.reply_len), ! 770: GETINT(sgp->hd.pack_id), ! 771: GETINT(sgp->hd.result), ! 772: sgp->hd.want_new, ! 773: sgp->hd.grant_new, ! 774: sgp->hd.cdb_len, ! 775: sgp->hd.sense_len, ! 776: sgp->hd.sense_buffer[0]); ! 777: #else ! 778: printf("pack_len: %d, reply_len: %d pack_id: %d result: %d sense[0]: %02X\n", ! 779: GETINT(sgp->hd.pack_len), ! 780: GETINT(sgp->hd.reply_len), ! 781: GETINT(sgp->hd.pack_id), ! 782: GETINT(sgp->hd.result), ! 783: sgp->hd.sense_buffer[0]); ! 784: #endif ! 785: #ifdef DEBUG ! 786: printf("sense: "); ! 787: for (i=0; i < 16; i++) ! 788: printf("%02X ", sgp->hd.sense_buffer[i]); ! 789: printf("\n"); ! 790: #endif ! 791: } ! 792: ! 793: if (sp->timeout != scgp->deftimeout) ! 794: sg_settimeout(f, scgp->deftimeout); ! 795: return 0; ! 796: } ! 797: ! 798: LOCAL ! 799: void scsitimes(scgp) ! 800: SCSI *scgp; ! 801: { ! 802: struct timeval *stp = scgp->cmdstop; ! 803: ! 804: gettimeofday(stp, (struct timezone *)0); ! 805: stp->tv_sec -= scgp->cmdstart->tv_sec; ! 806: stp->tv_usec -= scgp->cmdstart->tv_usec; ! 807: while (stp->tv_usec < 0) { ! 808: stp->tv_sec -= 1; ! 809: stp->tv_usec += 1000000; ! 810: } ! 811: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.