?? scsi-linux-sg.c
字號(hào):
/* @(#)scsi-linux-sg.c 1.39 99/09/17 Copyright 1997 J. Schilling */#ifndef lintstatic char __sccsid[] = "@(#)scsi-linux-sg.c 1.39 99/09/17 Copyright 1997 J. Schilling";#endif/* * Interface for Linux generic SCSI implementation (sg). * * This is the interface for the broken Linux SCSI generic driver. * This is a hack, that tries to emulate the functionality * of the scg driver. * * Design flaws of the sg driver: * - cannot see if SCSI command could not be send * - cannot get SCSI status byte * - cannot get real dma count of tranfer * - cannot get number of bytes valid in auto sense data * - to few data in auto sense (CCS/SCSI-2/SCSI-3 needs >= 18) * * This code contains support for the sg driver version 2 * * Warning: you may change this source, but if you do that * you need to change the _scg_version and _scg_auth* string below. * You may not return "schily" for an SCG_AUTHOR request anymore. * Choose your name instead of "schily" and make clear that the version * string is related to a modified source. * * Copyright (c) 1997 J. Schilling *//* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */#include <linux/version.h>#ifndef LINUX_VERSION_CODE /* Very old kernel? */# define LINUX_VERSION_CODE 0#endif#if LINUX_VERSION_CODE >= 0x01031a /* <linux/scsi.h> introduced in 1.3.26 */#if LINUX_VERSION_CODE >= 0x020000 /* <scsi/scsi.h> introduced somewhere. *//* Need to fine tune the ifdef so we get the transition point right. */#include <scsi/scsi.h>#else#include <linux/scsi.h>#endif#else#define __KERNEL__#include <linux/fs.h>#undef __KERNEL__#include "block/blk.h"#include "scsi/scsi.h"#endif#include "scsi/sg.h"/* * Warning: you may change this source, but if you do that * you need to change the _scg_version and _scg_auth* string below. * You may not return "schily" for an SCG_AUTHOR request anymore. * Choose your name instead of "schily" and make clear that the version * string is related to a modified source. */LOCAL char _scg_trans_version[] = "scsi-linux-sg.c-1.39"; /* The version for this transport*/#ifndef SCSI_IOCTL_GET_BUS_NUMBER#define SCSI_IOCTL_GET_BUS_NUMBER 0x5386#endif/* * XXX There must be a better way than duplicating things from system include * XXX files. This is stolen from /usr/src/linux/drivers/scsi/scsi.h */#ifndef DID_OK#define DID_OK 0x00 /* NO error */#define DID_NO_CONNECT 0x01 /* Couldn't connect before timeout period */#define DID_BUS_BUSY 0x02 /* BUS stayed busy through time out period */#define DID_TIME_OUT 0x03 /* TIMED OUT for other reason */#define DID_BAD_TARGET 0x04 /* BAD target. */#define DID_ABORT 0x05 /* Told to abort for some other reason */#define DID_PARITY 0x06 /* Parity error */#define DID_ERROR 0x07 /* Internal error */#define DID_RESET 0x08 /* Reset by somebody. */#define DID_BAD_INTR 0x09 /* Got an interrupt we weren't expecting. */ #endif/* * These indicate the error that occurred, and what is available. */#ifndef DRIVER_BUSY#define DRIVER_BUSY 0x01#define DRIVER_SOFT 0x02#define DRIVER_MEDIA 0x03#define DRIVER_ERROR 0x04 #define DRIVER_INVALID 0x05#define DRIVER_TIMEOUT 0x06#define DRIVER_HARD 0x07#define DRIVER_SENSE 0x08#endif/* * XXX Should add extra space in buscookies and scgfiles for a "PP bus" * XXX and for two "ATAPI busses". */#define MAX_SCG 16 /* Max # of SCSI controllers */#define MAX_TGT 16#define MAX_LUN 8struct scg_local { int scgfile; /* Used for SG_GET_BUFSIZE ioctl()*/ short scgfiles[MAX_SCG][MAX_TGT][MAX_LUN]; short buscookies[MAX_SCG]; int pgbus; int pack_id; /* Should be a random number */ char *SCSIbuf;};#define scglocal(p) ((struct scg_local *)((p)->local)) #ifdef SG_BIG_BUFF#define MAX_DMA_LINUX SG_BIG_BUFF /* Defined in include/scsi/sg.h */#else#define MAX_DMA_LINUX (4*1024) /* Old Linux versions */#endif#ifndef SG_MAX_SENSE# define SG_MAX_SENSE 16 /* Too small for CCS / SCSI-2 */#endif /* But cannot be changed */#if !defined(__i386) && !defined(i386) && !defined(mc68000)#define MISALIGN#endif/*#define MISALIGN*//*#undef SG_GET_BUFSIZE*/#if defined(USE_PG) && !defined(USE_PG_ONLY)#include "scsi-linux-pg.c"#endif#ifdef MISALIGNLOCAL int scsi_getint __PR((int *ip));#endifLOCAL int scsi_send __PR((SCSI *scgp, int f, struct scg_cmd *sp));LOCAL BOOL sg_setup __PR((SCSI *scgp, int f, int busno, int tgt, int tlun));LOCAL void sg_initdev __PR((SCSI *scgp, int f));LOCAL int sg_mapbus __PR((SCSI *scgp, int busno, int ino));LOCAL BOOL sg_mapdev __PR((SCSI *scgp, int f, int *busp, int *tgtp, int *lunp, int *chanp, int *inop));LOCAL void sg_settimeout __PR((int f, int timeout));/* * Return version information for the low level SCSI transport code. * This has been introduced to make it easier to trace down problems * in applications. */EXPORT char *scg__version(scgp, what) SCSI *scgp; int what;{ if (scgp != (SCSI *)0) { switch (what) { case SCG_VERSION: return (_scg_trans_version); /* * If you changed this source, you are not allowed to * return "schily" for the SCG_AUTHOR request. */ case SCG_AUTHOR: return (_scg_auth_schily); case SCG_SCCS_ID: return (__sccsid); } } return ((char *)0);}EXPORT intscsi_open(scgp, device, busno, tgt, tlun) SCSI *scgp; char *device; int busno; int tgt; int tlun;{ register int f; register int i; register int b; register int t; register int l; register int nopen = 0; char devname[64]; if (busno >= MAX_SCG || tgt >= MAX_TGT || tlun >= MAX_LUN) { errno = EINVAL; if (scgp->errstr) js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE, "Illegal value for busno, target or lun '%d,%d,%d'", busno, tgt, tlun); return (-1); } if (scgp->local == NULL) { scgp->local = malloc(sizeof(struct scg_local)); if (scgp->local == NULL) return (0); scglocal(scgp)->scgfile = -1; scglocal(scgp)->pgbus = -2; scglocal(scgp)->SCSIbuf = (char *)-1; scglocal(scgp)->pack_id = 5; for (b=0; b < MAX_SCG; b++) { scglocal(scgp)->buscookies[b] = (short)-1; for (t=0; t < MAX_TGT; t++) { for (l=0; l < MAX_LUN ; l++) scglocal(scgp)->scgfiles[b][t][l] = (short)-1; } } } if ((device != NULL && *device != '\0') || (busno == -2 && tgt == -2)) goto openbydev; for (i=0; i < 32; i++) { sprintf(devname, "/dev/sg%d", i); f = open(devname, 2); if (f < 0) { if (errno != ENOENT && errno != ENXIO && errno != ENODEV) { if (scgp->errstr) js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE, "Cannot open '%s'", devname); return (0); } } else { if (sg_setup(scgp, f, busno, tgt, tlun)) return (++nopen); if (busno < 0 && tgt < 0 && tlun < 0) nopen++; } } if (nopen == 0) for (i=0; i <= 25; i++) { sprintf(devname, "/dev/sg%c", i+'a'); f = open(devname, 2); if (f < 0) { if (errno != ENOENT && errno != ENXIO && errno != ENODEV) { if (scgp->errstr) js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE, "Cannot open '%s'", devname); return (0); } } else { if (sg_setup(scgp, f, busno, tgt, tlun)) return (++nopen); if (busno < 0 && tgt < 0 && tlun < 0) nopen++; } }openbydev: if (device != NULL && *device != '\0') { f = open(device, 2); if (f < 0 && errno == ENOENT) goto openpg; if (!sg_mapdev(scgp, f, &busno, &tgt, &tlun, 0, 0)) { close(f); goto openpg; } if (scgp->scsibus < 0) scgp->scsibus = busno; if (scgp->target < 0) scgp->target = tgt; if (scgp->lun < 0) scgp->lun = tlun; if (sg_setup(scgp, f, busno, tgt, tlun)) return (++nopen); }openpg:#ifdef USE_PG nopen += pg_open(scgp, device, busno, tgt, tlun);#endif if (scgp->debug) for (b=0; b < MAX_SCG; b++) { printf("Bus: %d cookie: %X\n", b, scglocal(scgp)->buscookies[b]); for (t=0; t < MAX_TGT; t++) { for (l=0; l < MAX_LUN ; l++) if (scglocal(scgp)->scgfiles[b][t][l] != (short)-1) printf("file (%d,%d,%d): %d\n", b, t, l, scglocal(scgp)->scgfiles[b][t][l]); } } return (nopen);}EXPORT intscsi_close(scgp) SCSI *scgp;{ register int f; register int b; register int t; register int l; if (scgp->local == NULL) return (-1); for (b=0; b < MAX_SCG; b++) { if (b == scglocal(scgp)->pgbus) continue; scglocal(scgp)->buscookies[b] = (short)-1; for (t=0; t < MAX_TGT; t++) { for (l=0; l < MAX_LUN ; l++) f = scglocal(scgp)->scgfiles[b][t][l]; if (f >= 0) close(f); scglocal(scgp)->scgfiles[b][t][l] = (short)-1; } }#ifdef USE_PG pg_close(scgp);#endif return (0);}LOCAL BOOLsg_setup(scgp, f, busno, tgt, tlun) SCSI *scgp; int f; int busno; int tgt; int tlun;{ int n; int Chan; int Ino; int Bus; int Target; int Lun; BOOL onetarget = FALSE; if (scgp->scsibus >= 0 && scgp->target >= 0 && scgp->lun >= 0) onetarget = TRUE; sg_mapdev(scgp, f, &Bus, &Target, &Lun, &Chan, &Ino); /* * For old kernels try to make the best guess. */ Ino |= Chan << 8; n = sg_mapbus(scgp, Bus, Ino); if (Bus == -1) { Bus = n; 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;
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -