📄 scsi-linux-sg.c
字号:
if (scgp->debug) printf("SCSI Bus: %d (mapped from %d)\n", Bus, Ino); } if (Bus < 0 || Bus >= MAX_SCG || Target < 0 || Target >= MAX_TGT || Lun < 0 || Lun >= MAX_LUN) { return (FALSE); } if (scglocal(scgp)->scgfiles[Bus][Target][Lun] == (short)-1) scglocal(scgp)->scgfiles[Bus][Target][Lun] = (short)f; if (onetarget) { if (Bus == busno && Target == tgt && Lun == tlun) { sg_initdev(scgp, f); scglocal(scgp)->scgfile = f; /* remember file for ioctl's */ return (TRUE); } else { scglocal(scgp)->scgfiles[Bus][Target][Lun] = (short)-1; close(f); } } else { sg_initdev(scgp, f); if (scglocal(scgp)->scgfile < 0) scglocal(scgp)->scgfile = f; /* remember file for ioctl's */ } return (FALSE);}LOCAL voidsg_initdev(scgp, f) SCSI *scgp; int f;{ struct sg_rep { struct sg_header hd; unsigned char rbuf[100]; } sg_rep; int n; /* Eat any unwanted garbage from prior use of this device */ n = fcntl(f, F_GETFL); /* Be very proper about this */ fcntl(f, F_SETFL, n|O_NONBLOCK); fillbytes((caddr_t)&sg_rep, sizeof(struct sg_header), '\0'); sg_rep.hd.reply_len = sizeof(struct sg_header); while (read(f, &sg_rep, sizeof(sg_rep)) >= 0 || errno != EAGAIN) ; fcntl(f, F_SETFL, n); sg_settimeout(f, scgp->deftimeout);}LOCAL intsg_mapbus(scgp, busno, ino) SCSI *scgp; int busno; int ino;{ register int i; if (busno >= 0 && busno < MAX_SCG) { /* * SCSI_IOCTL_GET_BUS_NUMBER worked. * Now we have the problem that Linux does not properly number * SCSI busses. The Bus number that Linux creates really is * the controller (card) number. I case of multi SCSI bus * cards we are lost. */ if (scglocal(scgp)->buscookies[busno] == (short)-1) { scglocal(scgp)->buscookies[busno] = ino; return (busno); } if (scglocal(scgp)->buscookies[busno] != (short)ino) errmsgno(EX_BAD, "Warning Linux Bus mapping botch.\n"); return (busno); } else for (i=0; i < MAX_SCG; i++) { if (scglocal(scgp)->buscookies[i] == (short)-1) { scglocal(scgp)->buscookies[i] = ino; return (i); } if (scglocal(scgp)->buscookies[i] == ino) return (i); } return (0);}LOCAL BOOLsg_mapdev(scgp, f, busp, tgtp, lunp, chanp, inop) SCSI *scgp; int f; int *busp; int *tgtp; int *lunp; int *chanp; int *inop;{ struct sg_id { long l1; /* target | lun << 8 | channel << 16 | low_ino << 24 */ long l2; /* Unique id */ } sg_id; int Chan; int Ino; int Bus; int Target; int Lun; if (ioctl(f, SCSI_IOCTL_GET_IDLUN, &sg_id)) return (FALSE); if (scgp->debug) printf("l1: 0x%lX l2: 0x%lX\n", sg_id.l1, sg_id.l2); if (ioctl(f, SCSI_IOCTL_GET_BUS_NUMBER, &Bus) < 0) { Bus = -1; } Target = sg_id.l1 & 0xFF; Lun = (sg_id.l1 >> 8) & 0xFF; Chan = (sg_id.l1 >> 16) & 0xFF; Ino = (sg_id.l1 >> 24) & 0xFF; if (scgp->debug) { printf("Bus: %d Target: %d Lun: %d Chan: %d Ino: %d\n", Bus, Target, Lun, Chan, Ino); } *busp = Bus; *tgtp = Target; *lunp = Lun; if (chanp) *chanp = Chan; if (inop) *inop = Ino; return (TRUE);}#if defined(SG_SET_RESERVED_SIZE) && defined(SG_GET_RESERVED_SIZE)/* * The way Linux does DMA resouce management is a bit curious. * It totally deviates from all other OS and forces long ugly code. * If we are opening all drivers for a SCSI bus scan operation, we need * to set the limit for all open devices. * This may use up all kernel memory ... so do the job carefully. * * A big problem is that SG_SET_RESERVED_SIZE does not return any hint * on whether the request did fail. The only way to find if it worked * is to use SG_GET_RESERVED_SIZE to read back the current values. */LOCAL longscsi_raisedma(scgp, newmax) SCSI *scgp; long newmax;{ register int b; register int t; register int l; register int f; int val; int old; /* * First try to raise the DMA limit to a moderate value that * most likely does not use up all kernel memory. */ val = 126*1024; if (val > MAX_DMA_LINUX) { for (b=0; b < MAX_SCG; b++) { for (t=0; t < MAX_TGT; t++) { for (l=0; l < MAX_LUN ; l++) { if ((f = scsi_fileno(scgp, b, t, l)) < 0) continue; old = 0; if (ioctl(f, SG_GET_RESERVED_SIZE, &old) < 0) continue; if (val > old) ioctl(f, SG_SET_RESERVED_SIZE, &val); } } } } /* * Now to raise the DMA limit to what we really need. */ if (newmax > val) { val = newmax; for (b=0; b < MAX_SCG; b++) { for (t=0; t < MAX_TGT; t++) { for (l=0; l < MAX_LUN ; l++) { if ((f = scsi_fileno(scgp, b, t, l)) < 0) continue; old = 0; if (ioctl(f, SG_GET_RESERVED_SIZE, &old) < 0) continue; if (val > old) ioctl(f, SG_SET_RESERVED_SIZE, &val); } } } } /* * To make sure we did not fail (the ioctl does not report errors) * we need to check the DMA limits. We return the smallest value. */ for (b=0; b < MAX_SCG; b++) { for (t=0; t < MAX_TGT; t++) { for (l=0; l < MAX_LUN ; l++) { if ((f = scsi_fileno(scgp, b, t, l)) < 0) continue; if (ioctl(f, SG_GET_RESERVED_SIZE, &val) < 0) continue; if (scgp->debug) printf("Target (%d,%d,%d): DMA max %d old max: %ld\n", b, t, l, val, newmax); if (val < newmax) newmax = val; } } } return ((long)newmax);}#endifLOCAL longscsi_maxdma(scgp, amt) SCSI *scgp; long amt;{ long maxdma = MAX_DMA_LINUX;#if defined(SG_SET_RESERVED_SIZE) && defined(SG_GET_RESERVED_SIZE) /* * Use the curious new kernel interface found on Linux >= 2.2.10 * This interface first appeared in 2.2.6 but it was not working. */ if (scglocal(scgp)->drvers >= 20134) maxdma = scsi_raisedma(scgp, amt);#endif#ifdef SG_GET_BUFSIZE /* * We assume that all /dev/sg instances use the same * maximum buffer size. */ maxdma = ioctl(scglocal(scgp)->scgfile, SG_GET_BUFSIZE, 0);#endif if (maxdma < 0) {#ifdef USE_PG /* * If we only have a Parallel port, just return PP maxdma. */ if (scglocal(scgp)->pgbus == 0) return (pg_maxdma(scgp, amt));#endif if (scglocal(scgp)->scgfile >= 0) maxdma = MAX_DMA_LINUX; }#ifdef USE_PG if (scgp->scsibus == scglocal(scgp)->pgbus) return (pg_maxdma(scgp, amt)); if ((scgp->scsibus < 0) && (pg_maxdma(scgp, amt) < maxdma)) return (pg_maxdma(scgp, amt));#endif return (maxdma);}EXPORT void *scsi_getbuf(scgp, amt) SCSI *scgp; long amt;{ char *ret; if (amt <= 0 || amt > scsi_bufsize(scgp, amt)) return ((void *)0); if (scgp->debug) printf("scsi_getbuf: %ld bytes\n", amt); /* * For performance reason, we allocate pagesize() * bytes before the SCSI buffer to avoid * copying the whole buffer contents when * setting up the /dev/sg data structures. */ ret = valloc((size_t)(amt+getpagesize())); if (ret == NULL) return (ret); scgp->bufbase = ret; ret += getpagesize(); scglocal(scgp)->SCSIbuf = ret; return ((void *)ret);}EXPORT voidscsi_freebuf(scgp) SCSI *scgp;{ if (scgp->bufbase) free(scgp->bufbase); scgp->bufbase = NULL;}EXPORTBOOL scsi_havebus(scgp, busno) SCSI *scgp; int busno;{ register int t; register int l; if (busno < 0 || busno >= MAX_SCG) return (FALSE); if (scgp->local == NULL) return (FALSE); for (t=0; t < MAX_TGT; t++) { for (l=0; l < MAX_LUN ; l++) if (scglocal(scgp)->scgfiles[busno][t][l] >= 0) return (TRUE); } return (FALSE);}EXPORTint scsi_fileno(scgp, busno, tgt, tlun) SCSI *scgp; int busno; int tgt; int tlun;{ if (busno < 0 || busno >= MAX_SCG || tgt < 0 || tgt >= MAX_TGT || tlun < 0 || tlun >= MAX_LUN) return (-1); if (scgp->local == NULL) return (-1); return ((int)scglocal(scgp)->scgfiles[busno][tgt][tlun]);}EXPORT intscsi_initiator_id(scgp) SCSI *scgp;{#ifdef USE_PG if (scgp->scsibus == scglocal(scgp)->pgbus) return (pg_initiator_id(scgp));#endif return (-1);}EXPORTint scsi_isatapi(scgp) SCSI *scgp;{#ifdef USE_PG if (scgp->scsibus == scglocal(scgp)->pgbus) return (pg_isatapi(scgp));#endif#ifdef SG_EMULATED_HOST { int emulated = FALSE; int f = scsi_fileno(scgp, scgp->scsibus, scgp->target, scgp->lun); if (ioctl(f, SG_EMULATED_HOST, &emulated) >= 0) return (emulated != 0); }#endif return (-1);}EXPORTint scsireset(scgp) SCSI *scgp;{#ifdef SG_SCSI_RESET int f = scsi_fileno(scgp, scgp->scsibus, scgp->target, scgp->lun); int func = 0;#endif#ifdef USE_PG if (scgp->scsibus == scglocal(scgp)->pgbus) return (pg_reset(scgp));#endif /* * Do we have a SCSI reset in the Linux sg driver? */#ifdef SG_SCSI_RESET /* * Newer Linux sg driver seem to finally implement it... */#ifdef SG_SCSI_RESET_NOTHING func = SG_SCSI_RESET_NOTHING; if (ioctl(f, SG_SCSI_RESET, &func) >= 0) {#ifdef SG_SCSI_RESET_DEVICE func = SG_SCSI_RESET_DEVICE; if (ioctl(f, SG_SCSI_RESET, &func) >= 0) return (0);#endif#ifdef SG_SCSI_RESET_BUS func = SG_SCSI_RESET_BUS; if (ioctl(f, SG_SCSI_RESET, &func) >= 0) return (0);#endif }#endif#endif return (-1);}LOCAL voidsg_settimeout(f, tmo)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -