Subject: Re: control tool for amr(4)
To: Andrew Doran <andrew@hairylemon.org>
From: Manuel Bouyer <bouyer@antioche.eu.org>
List: tech-kern
Date: 06/28/2006 13:41:18
--8t9RHnE3ZwKMSgU+
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
On Wed, Jun 28, 2006 at 11:18:59AM +0100, Andrew Doran wrote:
> I made a few more changes.. An uncompiled & untested diff is attached:
>
> - pass l->l_proc to bus_dmamap_load() so we don't need to double buffer
> - remove spl calls in amr_ioctl()
> - pass transfer direction in ld_amr_dobio()
Ops, thanks for catching this.
I've backed out one part of your change, about au_length and au_cmd[0]:
I think it's safer to reject au_cmd[0] == 0x06 (as we don't know for what this
is for) and au_length == 0. Sending a command that wants to transfers some
data without a buffer can cause some serious harms here, and amrstat uses
only a restricted set of commands anyway, which all wants to transfer some
data.
--
Manuel Bouyer, LIP6, Universite Paris VI. Manuel.Bouyer@lip6.fr
NetBSD: 26 ans d'experience feront toujours la difference
--
--8t9RHnE3ZwKMSgU+
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename=diff
? sys/dev/pci/amrio.h
Index: sys/dev/pci/Makefile
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/Makefile,v
retrieving revision 1.11
diff -u -r1.11 Makefile
--- sys/dev/pci/Makefile 6 Dec 2005 11:53:56 -0000 1.11
+++ sys/dev/pci/Makefile 28 Jun 2006 11:33:02 -0000
@@ -5,7 +5,7 @@
INCSDIR= /usr/include/dev/pci
# Only install includes which are used by userland
-INCS= if_lmc.h mlyio.h mlyreg.h \
+INCS= amrreg.h amrio.h if_lmc.h mlyio.h mlyreg.h \
pcidevs.h pcidevs_data.h pciio.h pcireg.h \
tgareg.h twereg.h tweio.h
Index: sys/dev/pci/amr.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/amr.c,v
retrieving revision 1.35
diff -u -r1.35 amr.c
--- sys/dev/pci/amr.c 7 Jun 2006 22:33:36 -0000 1.35
+++ sys/dev/pci/amr.c 28 Jun 2006 11:33:02 -0000
@@ -81,6 +81,7 @@
#include <sys/proc.h>
#include <sys/buf.h>
#include <sys/malloc.h>
+#include <sys/conf.h>
#include <sys/kthread.h>
#include <uvm/uvm_extern.h>
@@ -92,6 +93,7 @@
#include <dev/pci/pcivar.h>
#include <dev/pci/amrreg.h>
#include <dev/pci/amrvar.h>
+#include <dev/pci/amrio.h>
#include "locators.h"
@@ -115,9 +117,20 @@
static int amr_std_get_work(struct amr_softc *, struct amr_mailbox_resp *);
static int amr_std_submit(struct amr_softc *, struct amr_ccb *);
+static dev_type_open(amropen);
+static dev_type_close(amrclose);
+static dev_type_ioctl(amrioctl);
+
CFATTACH_DECL(amr, sizeof(struct amr_softc),
amr_match, amr_attach, NULL, NULL);
+const struct cdevsw amr_cdevsw = {
+ amropen, amrclose, noread, nowrite, amrioctl,
+ nostop, notty, nopoll, nommap,
+};
+
+extern struct cfdriver amr_cd;
+
#define AT_QUARTZ 0x01 /* `Quartz' chipset */
#define AT_SIG 0x02 /* Check for signature */
@@ -260,7 +273,7 @@
const char *intrstr;
pcireg_t reg;
int rseg, i, j, size, rv, memreg, ioreg;
- struct amr_ccb *ac;
+ struct amr_ccb *ac;
int locs[AMRCF_NLOCS];
aprint_naive(": RAID controller\n");
@@ -719,7 +732,7 @@
static void
amr_shutdown(void *cookie)
{
- extern struct cfdriver amr_cd;
+ extern struct cfdriver amr_cd;
struct amr_softc *amr;
struct amr_ccb *ac;
int i, rv, s;
@@ -872,7 +885,7 @@
ac->ac_cmd.mb_command = AMR_CMD_ENQUIRY;
rv = amr_ccb_map(amr, ac, amr->amr_enqbuf,
- AMR_ENQUIRY_BUFSIZE, 0);
+ AMR_ENQUIRY_BUFSIZE, AC_XFER_IN, NULL);
if (rv != 0) {
printf("%s: ccb_map failed (%d)\n",
amr->amr_dv.dv_xname, rv);
@@ -948,7 +961,8 @@
mb[2] = cmdsub;
mb[3] = cmdqual;
- rv = amr_ccb_map(amr, ac, sbuf, AMR_ENQUIRY_BUFSIZE, 0);
+ rv = amr_ccb_map(amr, ac, sbuf, AMR_ENQUIRY_BUFSIZE, AC_XFER_IN,
+ NULL);
if (rv == 0) {
rv = amr_ccb_poll(amr, ac, 2000);
amr_ccb_unmap(amr, ac);
@@ -1027,25 +1041,31 @@
*/
int
amr_ccb_map(struct amr_softc *amr, struct amr_ccb *ac, void *data, int size,
- int out)
+ int tflag, struct proc *p)
{
struct amr_sgentry *sge;
struct amr_mailbox_cmd *mb;
int nsegs, i, rv, sgloff;
bus_dmamap_t xfer;
+ int dmaflag = 0;
xfer = ac->ac_xfer_map;
- rv = bus_dmamap_load(amr->amr_dmat, xfer, data, size, NULL,
- BUS_DMA_NOWAIT);
+ rv = bus_dmamap_load(amr->amr_dmat, xfer, data, size, p,
+ (p != NULL ? BUS_DMA_WAITOK : BUS_DMA_NOWAIT));
if (rv != 0)
return (rv);
mb = &ac->ac_cmd;
ac->ac_xfer_size = size;
- ac->ac_flags |= (out ? AC_XFER_OUT : AC_XFER_IN);
+ ac->ac_flags |= (tflag & (AC_XFER_OUT | AC_XFER_IN));
sgloff = AMR_SGL_SIZE * ac->ac_ident;
+ if (tflag & AC_XFER_OUT)
+ dmaflag |= BUS_DMASYNC_PREWRITE;
+ if (tflag & AC_XFER_IN)
+ dmaflag |= BUS_DMASYNC_PREREAD;
+
/* We don't need to use a scatter/gather list for just 1 segment. */
nsegs = xfer->dm_nsegs;
if (nsegs == 1) {
@@ -1063,8 +1083,7 @@
}
}
- bus_dmamap_sync(amr->amr_dmat, xfer, 0, ac->ac_xfer_size,
- out ? BUS_DMASYNC_PREWRITE : BUS_DMASYNC_PREREAD);
+ bus_dmamap_sync(amr->amr_dmat, xfer, 0, ac->ac_xfer_size, dmaflag);
if ((ac->ac_flags & AC_NOSGL) == 0)
bus_dmamap_sync(amr->amr_dmat, amr->amr_dmamap, sgloff,
@@ -1079,14 +1098,19 @@
void
amr_ccb_unmap(struct amr_softc *amr, struct amr_ccb *ac)
{
+ int dmaflag = 0;
+
+ if (ac->ac_flags & AC_XFER_IN)
+ dmaflag |= BUS_DMASYNC_POSTREAD;
+ if (ac->ac_flags & AC_XFER_OUT)
+ dmaflag |= BUS_DMASYNC_POSTWRITE;
if ((ac->ac_flags & AC_NOSGL) == 0)
bus_dmamap_sync(amr->amr_dmat, amr->amr_dmamap,
AMR_SGL_SIZE * ac->ac_ident, AMR_SGL_SIZE,
BUS_DMASYNC_POSTWRITE);
bus_dmamap_sync(amr->amr_dmat, ac->ac_xfer_map, 0, ac->ac_xfer_size,
- (ac->ac_flags & AC_XFER_IN) != 0 ?
- BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
+ dmaflag);
bus_dmamap_unload(amr->amr_dmat, ac->ac_xfer_map);
}
@@ -1305,3 +1329,90 @@
printf("%08x ", ((u_int32_t *)&ac->ac_cmd)[i]);
printf("\n");
}
+
+static int
+amropen(dev_t dev, int flag, int mode, struct lwp *l)
+{
+ struct amr_softc *amr;
+
+ if ((amr = device_lookup(&amr_cd, minor(dev))) == NULL)
+ return (ENXIO);
+ if ((amr->amr_flags & AMRF_OPEN) != 0)
+ return (EBUSY);
+
+ amr->amr_flags |= AMRF_OPEN;
+ return (0);
+}
+
+static int
+amrclose(dev_t dev, int flag, int mode, struct lwp *l)
+{
+ struct amr_softc *amr;
+
+ amr = device_lookup(&amr_cd, minor(dev));
+ amr->amr_flags &= ~AMRF_OPEN;
+ return (0);
+}
+
+static int
+amrioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct lwp *l)
+{
+ struct amr_softc *amr;
+ struct amr_user_ioctl *au;
+ struct amr_ccb *ac;
+ struct amr_mailbox_ioctl *mbi;
+ unsigned long au_length;
+ uint8_t *au_cmd;
+ int error;
+
+ if (securelevel >= 2)
+ return (EPERM);
+
+ amr = device_lookup(&amr_cd, minor(dev));
+
+ /* This should be compatible with the FreeBSD interface */
+
+ switch (cmd) {
+ case AMR_IO_VERSION:
+ *(int *)data = AMR_IO_VERSION_NUMBER;
+ return 0;
+ case AMR_IO_COMMAND:
+ au = (struct amr_user_ioctl *)data;
+ au_cmd = au->au_cmd;
+ au_length = au->au_length;
+ break;
+ default:
+ return ENOTTY;
+ }
+
+ if (au_cmd[0] == AMR_CMD_PASS) {
+ /* not yet */
+ return EOPNOTSUPP;
+ }
+
+ if (au_length <= 0 || au_length > MAXPHYS || au_cmd[0] == 0x06)
+ return (EINVAL);
+
+ /* direct command to controller */
+ while (amr_ccb_alloc(amr, &ac) != 0) {
+ error = tsleep(NULL, PRIBIO | PCATCH, "armmbx", hz);
+ if (error == EINTR)
+ return (error);
+ }
+
+ mbi = (struct amr_mailbox_ioctl *)&ac->ac_cmd;
+ mbi->mb_command = au_cmd[0];
+ mbi->mb_channel = au_cmd[1];
+ mbi->mb_param = au_cmd[2];
+ mbi->mb_pad[0] = au_cmd[3];
+ mbi->mb_drive = au_cmd[4];
+ error = amr_ccb_map(amr, ac, au->au_buffer, (int)au_length,
+ AC_XFER_IN | AC_XFER_OUT, l->l_proc);
+ if (error == 0) {
+ error = amr_ccb_wait(amr, ac);
+ if (au_length != 0)
+ amr_ccb_unmap(amr, ac);
+ }
+ amr_ccb_free(amr, ac);
+ return error;
+}
Index: sys/dev/pci/amrreg.h
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/amrreg.h,v
retrieving revision 1.2
diff -u -r1.2 amrreg.h
--- sys/dev/pci/amrreg.h 4 May 2003 16:15:36 -0000 1.2
+++ sys/dev/pci/amrreg.h 28 Jun 2006 11:33:02 -0000
@@ -319,6 +319,7 @@
u_int32_t ae_drivesize[AMR_40LD_MAXDRIVES]; /* logical drive size */
u_int8_t ae_driveprop[AMR_40LD_MAXDRIVES]; /* logical drive properties */
u_int8_t ae_drivestate[AMR_40LD_MAXDRIVES]; /* physical drive state */
+ u_int8_t ae_pdrivestate[AMR_40LD_MAXPHYSDRIVES]; /* physical drive state */
u_int16_t ae_driveformat[AMR_40LD_MAXPHYSDRIVES];
u_int8_t ae_targxfer[80]; /* physical drive transfer rates */
Index: sys/dev/pci/amrvar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/amrvar.h,v
retrieving revision 1.5
diff -u -r1.5 amrvar.h
--- sys/dev/pci/amrvar.h 11 Dec 2005 12:22:48 -0000 1.5
+++ sys/dev/pci/amrvar.h 28 Jun 2006 11:33:02 -0000
@@ -107,6 +107,7 @@
/* General flags. */
#define AMRF_THREAD_EXIT 0x00010000
+#define AMRF_OPEN 0x00020000
/*
* Command control block.
@@ -143,7 +144,8 @@
int amr_ccb_alloc(struct amr_softc *, struct amr_ccb **);
void amr_ccb_enqueue(struct amr_softc *, struct amr_ccb *);
void amr_ccb_free(struct amr_softc *, struct amr_ccb *);
-int amr_ccb_map(struct amr_softc *, struct amr_ccb *, void *, int, int);
+int amr_ccb_map(struct amr_softc *, struct amr_ccb *, void *, int, int,
+ struct proc *);
int amr_ccb_poll(struct amr_softc *, struct amr_ccb *, int);
void amr_ccb_unmap(struct amr_softc *, struct amr_ccb *);
int amr_ccb_wait(struct amr_softc *, struct amr_ccb *);
Index: sys/dev/pci/ld_amr.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/ld_amr.c,v
retrieving revision 1.9
diff -u -r1.9 ld_amr.c
--- sys/dev/pci/ld_amr.c 25 Mar 2006 04:12:36 -0000 1.9
+++ sys/dev/pci/ld_amr.c 28 Jun 2006 11:33:02 -0000
@@ -151,7 +151,9 @@
mb->mb_blkcount = htole16(datasize / AMR_SECTOR_SIZE);
mb->mb_lba = htole32(blkno);
- if ((rv = amr_ccb_map(amr, ac, data, datasize, dowrite)) != 0) {
+ rv = amr_ccb_map(amr, ac, data, datasize,
+ (dowrite ? AC_XFER_OUT : AC_XFER_IN), NULL);
+ if (rv != 0) {
amr_ccb_free(amr, ac);
return (rv);
}
--8t9RHnE3ZwKMSgU+--