📄 gscdd.c
字号:
/* * $Id: gscdd.c,v 1.1 2001/04/15 11:12:37 ant Exp $ * Copyright (c) 1996, 1997 by Matthew Jacob * * This software is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; version 2. * * This software 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * The author may be reached via electronic communications at * * mjacob@feral.com * * or, via United States Postal Address * * Matthew Jacob * 1831 Castro Street * San Francisco, CA, 94131 */#include <stdio.h>#include <sys/types.h>#include <sys/errno.h>#include <sys/sysmacros.h>#include <sys/syspest.h>#include <sys/ioctl.h>#include <sys/i_machine.h>#include <sys/systm.h>#include <sys/conf.h>#include <sys/devinfo.h>#include <sys/lockl.h>#include <sys/device.h>#include <sys/uio.h>#include <sys/watchdog.h>#include <sys/errids.h>#include <sys/trchkid.h>#include <sys/priv.h>#include <sys/iostat.h>#include <sys/bootrecord.h>#include <sys/scsi.h>#include <sys/malloc.h>#include <sys/sleep.h>#include <sys/fp_io.h>#include <sys/pin.h>#include <sys/lock_alloc.h>#define DD_LOCK 37#include "gscdds.h"static int strlen(char *s) { char *p = s; while (*p) p++; return p - s; }static void memset(void *x, int val, size_t amt){ char *p = (char *)x; while (--amt) *p++ = (char) val; }static void memcpy(void *dst, void *src, size_t amt) { char *dest = dst, *source = src; while (--amt) *dest++ = *source++; }#define bcopy(src, dst, nbytes) memcpy(dst, src, nbytes)/* * Local Definitions */#define HKWD_GSC_DD 0x66600000#define _COM_TRACE(b, var) \ var = strlen(b); trcgenk(0, HKWD_GSC_DD, var, var, b)#define Trace0(val, str) \ if (scudebug >= val) { \ int icxq; \ _COM_TRACE(str, icxq); \ }#define Trace1(val, fmt, arg1) \ if (scudebug >= val) { \ int icxq; char buf[256]; \ (void) sprintf(buf, fmt, arg1); \ _COM_TRACE(buf, icxq); \ }#define Trace2(val, fmt, arg1, arg2) \ if (scudebug >= val) { \ int icxq; char buf[256]; \ (void) sprintf(buf, fmt, arg1, arg2); \ _COM_TRACE(buf, icxq); \ }#define Trace3(val, fmt, arg1, arg2, arg3) \ if (scudebug >= val) { \ int icxq; char buf[256]; \ (void) sprintf(buf, fmt, arg1, arg2, arg3); \ _COM_TRACE(buf, icxq); \ }#define Trace4(val, fmt, arg1, arg2, arg3, arg4) \ if (scudebug >= val) { \ int icxq; char buf[256]; \ (void) sprintf(buf, fmt, arg1, arg2, arg3, arg4); \ _COM_TRACE(buf, icxq); \ }#define Trace5(val, fmt, arg1, arg2, arg3, arg4, arg5) \ if (scudebug >= val) { \ int icxq; char buf[256]; \ (void) sprintf(buf, fmt, arg1, arg2, arg3, arg4, arg5); \ _COM_TRACE(buf, icxq); \ }#define Trace6(val, fmt, arg1, arg2, arg3, arg4, arg5, arg6) \ if (scudebug >= val) { \ int icxq; char buf[256]; \ (void) sprintf(buf, fmt, arg1, arg2, arg3, arg4, arg5, arg6); \ _COM_TRACE(buf, icxq); \ }#define MJ_RTN(VAL) simple_unlock(&sp->dd_lock); return (VAL)typedef struct { struct sc_buf scsibuf; uint index;} gsc_buf_t;typedef struct { Simple_lock dd_lock; Simple_lock buf_lock; struct file *fp; /* file pointer */ gsc_buf_t cbuf;#define cmdbuf cbuf.scsibuf /* buffer for command */ gsc_buf_t rbuf;#define rqsbuf rbuf.scsibuf /* buffer for request sense */ dev_t dev; /* Adapter dev */ u_char tgt; /* target ID */ u_char lun; /* logical unit */ u_char isopen; /* device is open */ u_char iscfg; /* non-zero to show this as configured */ u_char unstart; /* stop device on unconfigure */ u_char needresume; /* needs an SC_RESUME with next command */} gsc_softc_t;/* * External References */extern int copyin(void *, void *, int);extern int copyout(void *, void *, int);extern int devstrat(struct buf *);extern int nodev(void);extern void setuerror(int);/* * Device Driver Entry Points */int gsc_config(dev_t, int, struct uio *);static int gsc_open(dev_t);static int gsc_close(dev_t);static int gsc_ioctl(dev_t, int, void *, ulong);static void gscdd_intr(struct buf *);/* * Static Data */static int scudebug = 10;static int nunits = 0;static gsc_softc_t softinfo[MAX_UNITS] = { 0 };lock_t config_lock = { LOCK_AVAIL };/* * Local Function Prototypes */static int gsopen(gsc_softc_t *);static void gsclose(gsc_softc_t *, dev_t);static int gsccmd(dev_t, scmd_t *, ulong);static int make_rqs(gsc_softc_t *, char, char *, int, int);/* * Configuration Routines */intgsc_config(dev_t devno, int cmd, struct uio * uiop){ struct gsc_ddsinfo ddsinfo; gsc_softc_t *sp; int result, i, unit; extern int nodev(); static struct devsw gsc_dsw = { gsc_open, /* entry point for open routine */ gsc_close, /* entry point for close routine */ nodev, /* entry point for read routine */ nodev, /* entry point for write routine */ gsc_ioctl, /* entry point for ioctl routine */ nodev, /* entry point for strategy routine */ 0, /* pointer to tty device structure */ nodev, /* entry point for select routine */ gsc_config, /* entry point for config routine */ nodev, /* entry point for print routine */ nodev, /* entry point for dump routine */ nodev, /* entry point for mpx routine */ nodev, /* entry point for revoke routine */ NULL, /* pointer to device specific data */ NULL, /* select pointer */ DEV_MPSAFE }; if (lockl(&config_lock, LOCK_SHORT) != LOCK_SUCC) { return (EINVAL); } unit = minor(devno); if (unit < 0 || unit >= MAX_UNITS) { Trace2(0, "%d: bad unit %d", __LINE__, unit); result = EINVAL; unlockl(&config_lock); return (result); } switch (cmd) { case CFG_INIT: Trace2(2, "CFG_INIT: unit %d nunit %d\n", unit, nunits); /* * Initialize softinfo, first time around. */ if (nunits == 0) { memset(softinfo, 0, sizeof (softinfo)); } /* * Copy in DDS information */ uiomove((caddr_t) &ddsinfo, sizeof ddsinfo, UIO_WRITE, uiop); sp = &softinfo[unit]; if (sp->iscfg) { Trace1(0, "CFG_INIT: unit %d already configd", unit); result = EBUSY; break; } lock_alloc(&sp->dd_lock, LOCK_ALLOC_PIN, DD_LOCK, -1); lock_alloc(&sp->buf_lock, LOCK_ALLOC_PIN, DD_LOCK, -1); simple_lock_init(&sp->dd_lock); sp->dev = ddsinfo.busid; sp->tgt = ddsinfo.target; sp->lun = ddsinfo.lun; sp->cbuf.index = sp->rbuf.index = unit; /* * If this is the first time through: * Add entry to the device switch table to call this driver * Pin driver code. */ if (nunits == 0) { result = devswadd(devno, &gsc_dsw); if (result != 0) { Trace1(0, "CFG_INIT: devswadd result: %d", result); break; } result = pincode((int (*) ()) gscdd_intr); if (result) { Trace1(0, "CFG_INIT: pincode result: %d", result); devswdel(devno); break; } } sp->iscfg = 1; result = gsopen(sp); if (result) { Trace2(0, "CFG_INIT: gsopen returns %d for unit %d", result, unit); sp->iscfg = 0; gsclose(sp, devno); break; } if (nunits <= unit) nunits = unit + 1; sp->iscfg = 1; break; case CFG_TERM: Trace1(2, "CFG_TERM unit %d", unit); result = 0; sp = &softinfo[unit]; if (sp->iscfg == 0) { Trace1(0, "CFG_TERM: unit %d not already configd", unit); result = ENXIO; break; } else if (sp->isopen) { Trace1(0, "CFG_TERM: unit %d open", unit); result = EBUSY; break; } sp->iscfg = 0; /* block further actions */ gsclose(sp, devno); break; default: result = EINVAL; break; } unlockl(&config_lock); return (result);}/* * Validate that devno is indeed for a SCSI adapter, and set up stuff for it. */static intgsopen(gsc_softc_t * sp){ struct file *fp; int r; struct devinfo di; Trace2(2, "gsopen: %d.%d", major(sp->dev), minor(sp->dev)); sp->fp = NULL; r = fp_opendev(sp->dev, DREAD|DWRITE|DKERNEL, NULL, 0, &fp); if (r) { Trace3(0, "%d: fp_opendev unit %d=%d", __LINE__, sp->cbuf.index, r); return (r); } r = fp_ioctl(fp, IOCINFO, (caddr_t) &di, NULL); if (r) { Trace3(0, "%d: fp_ioctl unit %d=%d", __LINE__, sp->cbuf.index, r); (void) fp_close(fp); return (r); } if (di.devtype != DD_BUS || di.devsubtype != DS_SCSI) { Trace2(0, "%d: not SCSI bus on unit %d", __LINE__, sp->cbuf.index); (void) fp_close(fp); return (r); } sp->fp = fp; sp->unstart = 1; if (fp_ioctl(sp->fp, SCIOSTART, (caddr_t) IDLUN(sp->tgt, sp->lun), NULL)) { sp->unstart = 0; } return (0);}/* * Shut down a device */static voidgsclose(gsc_softc_t *sp, dev_t devno){ int i; if (sp->fp != NULL && sp->unstart) { (void) fp_ioctl(sp->fp, SCIOSTOP, (caddr_t) IDLUN(sp->tgt, sp->lun), NULL); sp->unstart = 0; } if (sp->fp) { (void) fp_close(sp->fp); sp->fp = NULL; } for (i = 0; i < MAX_UNITS; i++) { if (softinfo[i].iscfg) { Trace1(0, "gsclose: unit %d still confd", i); break; } } if (i == MAX_UNITS) { Trace0(0, "gsclose: All unconfigured now"); (void) devswdel(devno); unpincode((int (*) ()) gscdd_intr); }}/* * VFS entry points */static intgsc_open(dev_t devno){ gsc_softc_t *sp; int unit = minor(devno); Trace1(2, "gsc_open: open unit %d", unit); if (unit < 0 || unit >= MAX_UNITS) { return (ENODEV); } sp = &softinfo[unit]; if (sp->iscfg == 0 || sp->fp == NULL) { Trace2(0, "%d: bad unit (%d)", __LINE__, unit); return (ENODEV); } simple_lock(&sp->dd_lock); if (sp->isopen) { simple_unlock(&sp->dd_lock); return (EBUSY); } sp->isopen = 1; simple_unlock(&sp->dd_lock); return (0);}static intgsc_close(dev_t dev){ gsc_softc_t *sp; int unit = minor(dev); Trace1(2, "gsc_close: close unit %d", unit); if (unit < 0 || unit >= MAX_UNITS) { return (ENODEV); } sp = &softinfo[unit]; if (sp->iscfg == 0) { return (ENODEV); } simple_lock(&sp->dd_lock); sp->isopen = 0; simple_unlock(&sp->dd_lock); return (0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -