Subject: IBM ServeRAID driver, the first attempt
To: None <tech-kern@netbsd.org>
From: Tonnerre LOMBARD <tonnerre@bsdprojects.net>
List: tech-kern
Date: 05/15/2007 21:21:38
--rJwd6BRFiFCcLxzm
Content-Type: multipart/mixed; boundary="WIyZ46R2i8wDzkSu"
Content-Disposition: inline
--WIyZ46R2i8wDzkSu
Content-Type: text/plain; charset=utf-8
Content-Disposition: inline
Salut,
This patch adds support for the IBM ServeRAID. It compiles, but I don't
know for sure yet whether it boots. I only wanted to share the first
experience.
(The reason why I don't know yet whether it boots is that my Netfinity
needs some special config flags in order to boot at all, which I forgot
to set)
Still to do:
* Test whether it actually works ;-)
* Add it to the config files of other arches
* Make it MP safe once the SMP patches are that far
Tonnerre
--WIyZ46R2i8wDzkSu
Content-Type: text/plain; charset=utf-8
Content-Description: The patch adding IBM ServeRAID support
Content-Disposition: attachment; filename="ips.diff"
Content-Transfer-Encoding: quoted-printable
Index: arch/i386/conf/ALL
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/sys/arch/i386/conf/ALL,v
retrieving revision 1.73.2.4
diff -u -r1.73.2.4 arch/i386/conf/ALL
--- arch/i386/conf/ALL 20 Feb 2007 14:12:08 -0000 1.73.2.4
+++ arch/i386/conf/ALL 15 May 2007 02:06:54 -0000
@@ -632,6 +632,7 @@
bha* at pci? dev ? function ? # BusLogic 9xx SCSI
dpt* at pci? dev ? function ? # DPT SmartCache/SmartRAID
iha* at pci? dev ? function ? # Initio INIC-940/950 SCSI
+ips* at pci? dev ? function ? # IBM ServeRAID and compatible
isp* at pci? dev ? function ? # Qlogic ISP [12]0x0 SCSI/FibreChannel
mfi* at pci? dev ? function ? # LSI MegaRAID SAS
mly* at pci? dev ? function ? # Mylex AcceleRAID and eXtremeRAID
Index: arch/i386/conf/GENERIC
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/sys/arch/i386/conf/GENERIC,v
retrieving revision 1.799.2.5
diff -u -r1.799.2.5 arch/i386/conf/GENERIC
--- arch/i386/conf/GENERIC 22 Mar 2007 20:00:09 -0000 1.799.2.5
+++ arch/i386/conf/GENERIC 15 May 2007 02:06:54 -0000
@@ -640,6 +640,7 @@
bha* at pci? dev ? function ? # BusLogic 9xx SCSI
dpt* at pci? dev ? function ? # DPT SmartCache/SmartRAID
iha* at pci? dev ? function ? # Initio INIC-940/950 SCSI
+ips* at pci? dev ? function ? # IBM ServeRAID and compatible
isp* at pci? dev ? function ? # Qlogic ISP [12]0x0 SCSI/FibreChannel
mfi* at pci? dev ? function ? # LSI MegaRAID SAS
mly* at pci? dev ? function ? # Mylex AcceleRAID and eXtremeRAID
Index: arch/i386/conf/INSTALL
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/sys/arch/i386/conf/INSTALL,v
retrieving revision 1.297.2.4
diff -u -r1.297.2.4 arch/i386/conf/INSTALL
--- arch/i386/conf/INSTALL 28 Jan 2007 20:05:41 -0000 1.297.2.4
+++ arch/i386/conf/INSTALL 15 May 2007 02:06:54 -0000
@@ -339,6 +339,7 @@
bha* at pci? dev ? function ? # BusLogic 9xx SCSI
dpt* at pci? dev ? function ? # DPT SmartCache/SmartRAID
iha* at pci? dev ? function ? # Initio INIC-940/950 SCSI
+ips* at pci? dev ? function ? # IBM ServeRAID and compatible
isp* at pci? dev ? function ? # Qlogic ISP [12]0x0 SCSI/FibreChannel
mfi* at pci? dev ? function ? # LSI MegaRAID SAS
mly* at pci? dev ? function ? # Mylex AcceleRAID and eXtremeRAID
Index: arch/i386/conf/XEN2_DOM0
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/sys/arch/i386/conf/XEN2_DOM0,v
retrieving revision 1.18.2.3
diff -u -r1.18.2.3 arch/i386/conf/XEN2_DOM0
--- arch/i386/conf/XEN2_DOM0 19 Jan 2007 22:28:04 -0000 1.18.2.3
+++ arch/i386/conf/XEN2_DOM0 15 May 2007 02:06:54 -0000
@@ -409,6 +409,7 @@
bha* at pci? dev ? function ? # BusLogic 9xx SCSI
dpt* at pci? dev ? function ? # DPT SmartCache/SmartRAID
iha* at pci? dev ? function ? # Initio INIC-940/950 SCSI
+ips* at pci? dev ? function ? # IBM ServeRAID and compatible
isp* at pci? dev ? function ? # Qlogic ISP [12]0x0 SCSI/FibreChannel
mfi* at pci? dev ? function ? # LSI MegaRAID SAS
mly* at pci? dev ? function ? # Mylex AcceleRAID and eXtremeRAID
Index: dev/pci/files.pci
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/sys/dev/pci/files.pci,v
retrieving revision 1.273.2.2
diff -u -r1.273.2.2 files.pci
--- dev/pci/files.pci 21 Dec 2006 13:44:01 -0000 1.273.2.2
+++ dev/pci/files.pci 15 May 2007 02:00:26 -0000
@@ -142,6 +142,11 @@
attach mpt at pci with mpt_pci
file dev/pci/mpt_pci.c mpt_pci
=20
+# IBM ServeRAID controllers
+device ips: scsi
+attach ips at pci
+file dev/pci/ips.c ips
+
# Ethernet driver for DC21040-based boards
device de: ether, ifnet, arp
attach de at pci
Index: dev/pci/ips.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/sys/dev/pci/ips.c,v
--- /dev/null 2007-05-15 05:51:52.000000000 +0200
+++ dev/pci/ips.c 2007-05-15 05:34:10.000000000 +0200
@@ -0,0 +1,830 @@
+/* $OpenBSD: ips.c,v 1.16 2006/11/29 18:18:39 grange Exp $ */
+
+/*
+ * Copyright (c) 2006 Alexander Yurchenko <grange@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * IBM ServeRAID controller driver.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/buf.h>
+#include <sys/device.h>
+#include <sys/endian.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+
+#include <machine/bus.h>
+
+/* SCSI includes go here */
+#include <dev/scsipi/scsi_all.h>
+#include <dev/scsipi/scsi_disk.h>
+#include <dev/scsipi/scsipi_all.h>
+#include <dev/scsipi/scsipi_disk.h>
+#include <dev/scsipi/scsiconf.h>
+
+#include <dev/pci/pcidevs.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+
+#define IPS_DEBUG /* XXX: remove when the driver becomes stable */
+
+/* Debug levels */
+#define IPS_D_ERR 0x0001
+#define IPS_D_INFO 0x0002
+#define IPS_D_XFER 0x0004
+#define IPS_D_INTR 0x0008
+
+#ifdef IPS_DEBUG
+#define DPRINTF(a, b) if (ips_debug & (a)) printf b
+int ips_debug =3D IPS_D_ERR;
+#else
+#define DPRINTF(a, b)
+#endif
+
+/*
+ * Register definitions.
+ */
+#define IPS_BAR0 0x10 /* I/O space base address */
+#define IPS_BAR1 0x14 /* I/O space base address */
+
+#define IPS_MORPHEUS_OISR 0x0030 /* outbound IRQ status */
+#define IPS_MORPHEUS_OISR_CMD (1 << 3)
+#define IPS_MORPHEUS_OIMR 0x0034 /* outbound IRQ mask */
+#define IPS_MORPHEUS_IQPR 0x0040 /* inbound queue port */
+#define IPS_MORPHEUS_OQPR 0x0044 /* outbound queue port */
+#define IPS_MORPHEUS_OQPR_ID(x) (((x) >> 8) & 0xff)
+#define IPS_MORPHEUS_OQPR_ST(x) (((x) >> 16) & 0xff)
+#define IPS_MORPHEUS_OQPR_GSC(x) (((x) >> 16) & 0x0f)
+#define IPS_MORPHEUS_OQPR_EST(x) (((x) >> 24) & 0xff)
+#define IPS_MORPHEUS_GSC_NOERR 0x0
+#define IPS_MORPHEUS_GSC_RECOV 0x1
+
+/* Commands */
+#define IPS_CMD_READ 0x02
+#define IPS_CMD_WRITE 0x03
+#define IPS_CMD_ADAPTERINFO 0x05
+#define IPS_CMD_FLUSHCACHE 0x0a
+#define IPS_CMD_READ_SG 0x82
+#define IPS_CMD_WRITE_SG 0x83
+#define IPS_CMD_DRIVEINFO 0x19
+
+#define IPS_MAXCMDSZ 256 /* XXX: for now */
+#define IPS_MAXDATASZ 64 * 1024
+#define IPS_MAXSEGS 32
+
+#define IPS_MAXDRIVES 8
+#define IPS_MAXCHANS 4
+#define IPS_MAXTARGETS 15
+#define IPS_MAXCMDS 32
+
+#define IPS_MAXFER (64 * 1024)
+#define IPS_MAXSGS 32
+
+/* Command frames */
+struct ips_cmd_adapterinfo {
+ u_int8_t command;
+ u_int8_t id;
+ u_int8_t reserve1;
+ u_int8_t commandtype;
+ u_int32_t reserve2;
+ u_int32_t buffaddr;
+ u_int32_t reserve3;
+} __packed;
+
+struct ips_cmd_driveinfo {
+ u_int8_t command;
+ u_int8_t id;
+ u_int8_t drivenum;
+ u_int8_t reserve1;
+ u_int32_t reserve2;
+ u_int32_t buffaddr;
+ u_int32_t reserve3;
+} __packed;
+
+struct ips_cmd_generic {
+ u_int8_t command;
+ u_int8_t id;
+ u_int8_t drivenum;
+ u_int8_t reserve2;
+ u_int32_t lba;
+ u_int32_t buffaddr;
+ u_int32_t reserve3;
+} __packed;
+
+struct ips_cmd_io {
+ u_int8_t command;
+ u_int8_t id;
+ u_int8_t drivenum;
+ u_int8_t segnum;
+ u_int32_t lba;
+ u_int32_t buffaddr;
+ u_int16_t length;
+ u_int16_t reserve1;
+} __packed;
+
+/* Data frames */
+struct ips_adapterinfo {
+ u_int8_t drivecount;
+ u_int8_t miscflags;
+ u_int8_t SLTflags;
+ u_int8_t BSTflags;
+ u_int8_t pwr_chg_count;
+ u_int8_t wrong_addr_count;
+ u_int8_t unident_count;
+ u_int8_t nvram_dev_chg_count;
+ u_int8_t codeblock_version[8];
+ u_int8_t bootblock_version[8];
+ u_int32_t drive_sector_count[IPS_MAXDRIVES];
+ u_int8_t max_concurrent_cmds;
+ u_int8_t max_phys_devices;
+ u_int16_t flash_prog_count;
+ u_int8_t defunct_disks;
+ u_int8_t rebuildflags;
+ u_int8_t offline_drivecount;
+ u_int8_t critical_drivecount;
+ u_int16_t config_update_count;
+ u_int8_t blockedflags;
+ u_int8_t psdn_error;
+ u_int16_t addr_dead_disk[IPS_MAXCHANS][IPS_MAXTARGETS];
+} __packed;
+
+struct ips_drive {
+ u_int8_t drivenum;
+ u_int8_t merge_id;
+ u_int8_t raid_lvl;
+ u_int8_t state;
+ u_int32_t sector_count;
+} __packed;
+
+struct ips_driveinfo {
+ u_int8_t drivecount;
+ u_int8_t reserve1;
+ u_int16_t reserve2;
+ struct ips_drive drives[IPS_MAXDRIVES];
+} __packed;
+
+/* I/O access helper macros */
+#define IPS_READ_4(s, r) \
+ le32toh(bus_space_read_4((s)->sc_iot, (s)->sc_ioh, (r)))
+#define IPS_WRITE_4(s, r, v) \
+ bus_space_write_4((s)->sc_iot, (s)->sc_ioh, (r), htole32((v)))
+
+struct ccb {
+ int c_id;
+ int c_flags;
+#define CCB_F_RUN 0x0001
+
+ bus_dmamap_t c_dmam;
+ struct scsipi_xfer * c_xfer;
+
+ TAILQ_ENTRY(ccb) c_link;
+};
+
+TAILQ_HEAD(ccbq, ccb);
+
+struct dmamem {
+ bus_dma_tag_t dm_tag;
+ bus_dmamap_t dm_map;
+ bus_dma_segment_t dm_seg;
+ bus_size_t dm_size;
+ void * dm_kva;
+};
+
+struct ips_softc {
+ struct device sc_dev;
+
+ struct scsibus_softc * sc_scsi_bus;
+ struct scsipi_adapter sc_adapter;
+ struct scsipi_channel sc_channel;
+
+ pci_chipset_tag_t sc_pc;
+ pcitag_t sc_tag;
+
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+ bus_dma_tag_t sc_dmat;
+
+ struct dmamem * sc_cmdm;
+
+ struct ccb * sc_ccb;
+ struct ccbq sc_ccbq;
+
+ void * sc_ih;
+
+ void (*sc_exec)(struct ips_softc *);
+ void (*sc_inten)(struct ips_softc *);
+ int (*sc_intr)(void *);
+
+ struct ips_adapterinfo sc_ai;
+ struct ips_driveinfo sc_di;
+};
+
+int ips_match(struct device *, struct cfdata *, void *);
+void ips_attach(struct device *, struct device *, void *);
+
+void ips_scsi_cmd(struct scsipi_channel *, scsipi_adapter_req_t, void *);
+void ips_scsi_io(struct scsipi_xfer *, struct ips_softc *);
+static int ips_scsi_ioctl(struct scsipi_channel *, u_long, caddr_t, int,
+ struct proc *);
+void ips_scsi_minphys(struct buf *);
+
+void ips_xfer_timeout(void *);
+
+void ips_flushcache(struct ips_softc *);
+int ips_getadapterinfo(struct ips_softc *, struct ips_adapterinfo *);
+int ips_getdriveinfo(struct ips_softc *, struct ips_driveinfo *);
+
+void ips_copperhead_exec(struct ips_softc *);
+void ips_copperhead_inten(struct ips_softc *);
+int ips_copperhead_intr(void *);
+
+void ips_morpheus_exec(struct ips_softc *);
+void ips_morpheus_inten(struct ips_softc *);
+int ips_morpheus_intr(void *);
+
+struct ccb * ips_ccb_alloc(bus_dma_tag_t, int);
+void ips_ccb_free(struct ccb *, bus_dma_tag_t, int);
+
+struct dmamem * ips_dmamem_alloc(bus_dma_tag_t, bus_size_t);
+void ips_dmamem_free(struct dmamem *);
+
+CFATTACH_DECL(ips, sizeof(struct ips_softc),
+ ips_match, ips_attach, NULL, NULL);
+
+static const struct {
+ int vendor;
+ int product;
+} ips_ids[] =3D {
+ { PCI_VENDOR_IBM, PCI_PRODUCT_IBM_SERVERAID },
+ { PCI_VENDOR_IBM, PCI_PRODUCT_IBM_SERVERAID4 },
+ { PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_SERVERAID },
+ { 0, 0 }
+};
+
+int
+ips_match(struct device *parent, struct cfdata *match, void *aux)
+{
+ struct pci_attach_args *pa =3D aux;
+ pcireg_t reg =3D pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
+ int i;
+
+ for (i =3D 0; ips_ids[i].vendor; i++)
+ {
+ if ((PCI_VENDOR(pa->pa_id) =3D=3D ips_ids[i].vendor &&
+ PCI_PRODUCT(pa->pa_id) =3D=3D ips_ids[i].product) ||
+ (PCI_VENDOR(reg) =3D=3D ips_ids[i].vendor &&
+ PCI_PRODUCT(reg) =3D=3D ips_ids[i].product))
+ return 1;
+ }
+
+ return 0;
+}
+
+void
+ips_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct ips_softc *sc =3D (struct ips_softc *)self;
+ struct pci_attach_args *pa =3D aux;
+ int bar;
+ pcireg_t maptype;
+ bus_size_t iosize;
+ pci_intr_handle_t ih;
+ const char *intrstr;
+ int i, maxcmds;
+
+ sc->sc_pc =3D pa->pa_pc;
+ sc->sc_tag =3D pa->pa_tag;
+ sc->sc_dmat =3D pa->pa_dmat;
+
+ /* Identify the chipset */
+ switch (PCI_PRODUCT(pa->pa_id)) {
+ case PCI_PRODUCT_IBM_SERVERAID:
+ printf(": Copperhead");
+ sc->sc_exec =3D ips_copperhead_exec;
+ sc->sc_inten =3D ips_copperhead_inten;
+ sc->sc_intr =3D ips_copperhead_intr;
+ break;
+ case PCI_PRODUCT_IBM_SERVERAID4:
+ case PCI_PRODUCT_ADP2_SERVERAID:
+ printf(": Morpheus");
+ sc->sc_exec =3D ips_morpheus_exec;
+ sc->sc_inten =3D ips_morpheus_inten;
+ sc->sc_intr =3D ips_morpheus_intr;
+ break;
+ }
+
+ /* Map I/O space */
+ if (PCI_PRODUCT(pa->pa_id) =3D=3D PCI_PRODUCT_IBM_SERVERAID)
+ bar =3D IPS_BAR1;
+ else
+ bar =3D IPS_BAR0;
+ maptype =3D pci_mapreg_type(sc->sc_pc, sc->sc_tag, bar);
+ if (pci_mapreg_map(pa, bar, maptype, 0, &sc->sc_iot, &sc->sc_ioh,
+ NULL, &iosize)) {
+ printf(": can't map I/O space\n");
+ return;
+ }
+
+ /* Allocate command DMA buffer */
+ if ((sc->sc_cmdm =3D ips_dmamem_alloc(sc->sc_dmat,
+ IPS_MAXCMDSZ)) =3D=3D NULL) {
+ printf(": can't alloc command DMA buffer\n");
+ goto fail1;
+ }
+
+ /* Get adapter info */
+ if (ips_getadapterinfo(sc, &sc->sc_ai)) {
+ printf(": can't get adapter info\n");
+ goto fail2;
+ }
+
+ /* Get logical drives info */
+ if (ips_getdriveinfo(sc, &sc->sc_di)) {
+ printf(": can't get drives info\n");
+ goto fail2;
+ }
+
+ /* Allocate command queue */
+ maxcmds =3D sc->sc_ai.max_concurrent_cmds;
+ if ((sc->sc_ccb =3D ips_ccb_alloc(sc->sc_dmat, maxcmds)) =3D=3D NULL) {
+ printf(": can't alloc command queue\n");
+ goto fail2;
+ }
+
+ TAILQ_INIT(&sc->sc_ccbq);
+ for (i =3D 0; i < maxcmds; i++)
+ TAILQ_INSERT_TAIL(&sc->sc_ccbq, &sc->sc_ccb[i], c_link);
+
+ /* Install interrupt handler */
+ if (pci_intr_map(pa, &ih)) {
+ printf(": can't map interrupt\n");
+ goto fail3;
+ }
+ intrstr =3D pci_intr_string(sc->sc_pc, ih);
+ if ((sc->sc_ih =3D pci_intr_establish(sc->sc_pc, ih, IPL_BIO,
+ sc->sc_intr, sc)) =3D=3D NULL) {
+ printf(": can't establish interrupt");
+ if (intrstr !=3D NULL)
+ printf(" at %s", intrstr);
+ printf("\n");
+ goto fail3;
+ }
+ printf(", %s\n", intrstr);
+
+ /* Enable interrupts */
+ (*sc->sc_inten)(sc);
+
+ /* Attach SCSI bus */
+ sc->sc_channel.chan_adapter =3D &sc->sc_adapter;
+ sc->sc_channel.chan_bustype =3D &scsi_bustype;
+ sc->sc_channel.chan_channel =3D 0;
+ sc->sc_channel.chan_ntargets =3D IPS_MAXTARGETS;
+ sc->sc_channel.chan_nluns =3D 8;
+ sc->sc_channel.chan_flags =3D 0;
+ sc->sc_channel.chan_id =3D IPS_MAXTARGETS;
+ /* XXX: What about chan_openings? */
+
+ sc->sc_adapter.adapt_dev =3D (struct device *) sc;
+ sc->sc_adapter.adapt_max_periph =3D IPS_MAXTARGETS;
+ /* XXX: What about adapt_openings? */
+ sc->sc_adapter.adapt_request =3D &ips_scsi_cmd;
+ sc->sc_adapter.adapt_minphys =3D &ips_scsi_minphys;
+ sc->sc_adapter.adapt_ioctl =3D &ips_scsi_ioctl;
+
+ /* sc->sc_scsi_bus =3D (struct scsibus_softc *)config_found(self, &saa,
+ scsiprint); */
+
+ return;
+fail3:
+ ips_ccb_free(sc->sc_ccb, sc->sc_dmat, maxcmds);
+fail2:
+ ips_dmamem_free(sc->sc_cmdm);
+fail1:
+ bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize);
+}
+
+void
+ips_scsi_cmd(struct scsipi_channel *chan, scsipi_adapter_req_t req, void *=
arg)
+{
+ struct scsipi_xfer *xs =3D (struct scsipi_xfer *) arg;
+ struct scsipi_periph *periph =3D xs->xs_periph;
+ struct ips_softc *sc =3D
+ (struct ips_softc *) chan->chan_adapter->adapt_dev;
+ struct scsipi_inquiry_data *inq;
+ struct scsipi_read_capacity_10_data *cap;
+ struct scsi_sense_data *sns;
+ int target =3D periph->periph_target;
+ int s;
+
+ if (target >=3D sc->sc_di.drivecount || periph->periph_lun !=3D 0)
+ goto error;
+
+ switch (xs->cmd->opcode) {
+ case READ_10:
+ case SCSI_READ_6_COMMAND:
+ case WRITE_10:
+ case SCSI_WRITE_6_COMMAND:
+ ips_scsi_io(xs, sc);
+ return;
+ case INQUIRY:
+ inq =3D (void *)xs->data;
+ bzero(inq, sizeof(*inq));
+ inq->device =3D T_DIRECT;
+ inq->version =3D 2;
+ inq->response_format =3D 2;
+ inq->additional_length =3D 32;
+ strlcpy(inq->vendor, "IBM", sizeof(inq->vendor));
+ snprintf(inq->product, sizeof(inq->product),
+ "ServeRAID LD %02d", target);
+ goto done;
+ case READ_CAPACITY_10:
+ cap =3D (void *)xs->data;
+ bzero(cap, sizeof(*cap));
+ _lto4b(sc->sc_di.drives[target].sector_count - 1, cap->addr);
+ _lto4b(512, cap->length);
+ goto done;
+ case REQUEST_SENSE:
+ sns =3D (void *)xs->data;
+ bzero(sns, sizeof(*sns));
+ sns->response_code =3D 0x70;
+ sns->flags =3D SKEY_NO_SENSE;
+ goto done;
+ case SCSI_SYNCHRONIZE_CACHE_10:
+ ips_flushcache(sc);
+ goto done;
+ case SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL:
+ case START_STOP:
+ case TEST_UNIT_READY:
+ return;
+ }
+
+error:
+ xs->error =3D XS_DRIVER_STUFFUP;
+done:
+ s =3D splbio();
+ scsipi_done(xs);
+ splx(s);
+}
+
+void
+ips_scsi_io(struct scsipi_xfer *xs, struct ips_softc *sc)
+{
+ struct scsipi_periph *periph =3D xs->xs_periph;
+ struct scsipi_rw_10 *rw;
+ struct scsipi_rw_16 *rwb;
+ struct ccb *ccb;
+ struct ips_cmd_io *cmd;
+ u_int32_t blkno, blkcnt;
+ int i, s;
+
+ /* Pick up the first free ccb */
+ s =3D splbio();
+ ccb =3D TAILQ_FIRST(&sc->sc_ccbq);
+ if (ccb !=3D NULL)
+ TAILQ_REMOVE(&sc->sc_ccbq, ccb, c_link);
+ splx(s);
+ if (ccb =3D=3D NULL)
+ {
+ DPRINTF(IPS_D_ERR, ("%s: scsi_io, no free ccb\n",
+ sc->sc_dev.dv_xname));
+ return;
+ }
+
+ DPRINTF(IPS_D_XFER, ("%s: scsi_io, ccb id %d\n", sc->sc_dev.dv_xname,
+ ccb->c_id));
+
+ bus_dmamap_load(sc->sc_dmat, ccb->c_dmam, xs->data, xs->datalen, NULL,
+ BUS_DMA_NOWAIT);
+ ccb->c_xfer =3D xs;
+
+ if (xs->cmd->opcode =3D=3D SCSI_READ_6_COMMAND ||
+ xs->cmd->opcode =3D=3D SCSI_WRITE_6_COMMAND) {
+ u_int32_t length;
+ rw =3D (void *)xs->cmd;
+ length =3D _4btol(rw->length);
+ blkno =3D _3btol(rw->addr) & (SRW_TOPADDR << 16 | 0xffff);
+ blkcnt =3D length > 0 ? length : 0x100;
+ } else {
+ rwb =3D (void *)xs->cmd;
+ blkno =3D _4btol(rwb->addr);
+ blkcnt =3D _2btol(rwb->length);
+ }
+
+ cmd =3D sc->sc_cmdm->dm_kva;
+ bzero(cmd, sizeof(*cmd));
+ cmd->command =3D (xs->xs_control & XS_CTL_DATA_IN) ? IPS_CMD_READ :
+ IPS_CMD_WRITE;
+ cmd->id =3D ccb->c_id;
+ cmd->drivenum =3D periph->periph_target;
+ cmd->lba =3D blkno;
+ cmd->length =3D blkcnt;
+ if (ccb->c_dmam->dm_nsegs > 1) {
+ cmd->command =3D (xs->xs_control & XS_CTL_DATA_IN) ?
+ IPS_CMD_READ_SG : IPS_CMD_WRITE_SG;
+ cmd->segnum =3D ccb->c_dmam->dm_nsegs;
+
+ for (i =3D 0; i < ccb->c_dmam->dm_nsegs; i++) {
+ *(u_int32_t *)((u_int8_t *)sc->sc_cmdm->dm_kva + 24 +
+ i * 8) =3D ccb->c_dmam->dm_segs[i].ds_addr;
+ *(u_int32_t *)((u_int8_t *)sc->sc_cmdm->dm_kva + 24 +
+ i * 8 + 4) =3D ccb->c_dmam->dm_segs[i].ds_len;
+ }
+ cmd->buffaddr =3D sc->sc_cmdm->dm_seg.ds_addr + 24;
+ } else {
+ cmd->buffaddr =3D ccb->c_dmam->dm_segs[0].ds_addr;
+ }
+
+ callout_setfunc(&xs->xs_callout, ips_xfer_timeout, ccb);
+ callout_schedule(&xs->xs_callout, (xs->timeout * 1000) / hz);
+
+ s =3D splbio();
+ (*sc->sc_exec)(sc);
+ ccb->c_flags |=3D CCB_F_RUN;
+ splx(s);
+}
+
+static int
+ips_scsi_ioctl(struct scsipi_channel *chan, u_long cmd, caddr_t addr, int =
flags,
+ struct proc *p)
+{
+ return (ENOTTY);
+}
+
+void
+ips_scsi_minphys(struct buf *bp)
+{
+ minphys(bp);
+}
+
+void
+ips_xfer_timeout(void *arg)
+{
+ struct ccb *ccb =3D arg;
+ struct scsipi_xfer *xs =3D ccb->c_xfer;
+ struct ips_softc *sc =3D (struct ips_softc *) xs->xs_periph->
+ periph_channel->chan_adapter->adapt_dev;
+ int s;
+
+ DPRINTF(IPS_D_ERR, ("%s: xfer timeout, ccb id %d\n",
+ sc->sc_dev.dv_xname, ccb->c_id));
+
+ bus_dmamap_unload(sc->sc_dmat, ccb->c_dmam);
+ xs->error =3D XS_TIMEOUT;
+ s =3D splbio();
+ scsipi_done(xs);
+ ccb->c_flags &=3D ~CCB_F_RUN;
+ TAILQ_INSERT_TAIL(&sc->sc_ccbq, ccb, c_link);
+ splx(s);
+}
+
+void
+ips_flushcache(struct ips_softc *sc)
+{
+ struct ips_cmd_generic *cmd;
+
+ cmd =3D sc->sc_cmdm->dm_kva;
+ cmd->command =3D IPS_CMD_FLUSHCACHE;
+
+ (*sc->sc_exec)(sc);
+ DELAY(1000);
+}
+
+int
+ips_getadapterinfo(struct ips_softc *sc, struct ips_adapterinfo *ai)
+{
+ struct dmamem *dm;
+ struct ips_cmd_adapterinfo *cmd;
+
+ if ((dm =3D ips_dmamem_alloc(sc->sc_dmat, sizeof(*ai))) =3D=3D NULL)
+ return (1);
+
+ cmd =3D sc->sc_cmdm->dm_kva;
+ bzero(cmd, sizeof(*cmd));
+ cmd->command =3D IPS_CMD_ADAPTERINFO;
+ cmd->buffaddr =3D dm->dm_seg.ds_addr;
+
+ (*sc->sc_exec)(sc);
+ DELAY(1000);
+ bcopy(dm->dm_kva, ai, sizeof(*ai));
+ ips_dmamem_free(dm);
+
+ return (0);
+}
+
+int
+ips_getdriveinfo(struct ips_softc *sc, struct ips_driveinfo *di)
+{
+ struct dmamem *dm;
+ struct ips_cmd_driveinfo *cmd;
+
+ if ((dm =3D ips_dmamem_alloc(sc->sc_dmat, sizeof(*di))) =3D=3D NULL)
+ return (1);
+
+ cmd =3D sc->sc_cmdm->dm_kva;
+ bzero(cmd, sizeof(*cmd));
+ cmd->command =3D IPS_CMD_DRIVEINFO;
+ cmd->buffaddr =3D dm->dm_seg.ds_addr;
+
+ (*sc->sc_exec)(sc);
+ DELAY(1000);
+ bcopy(dm->dm_kva, di, sizeof(*di));
+ ips_dmamem_free(dm);
+
+ return (0);
+}
+
+void
+ips_copperhead_exec(struct ips_softc *sc)
+{
+}
+
+void
+ips_copperhead_inten(struct ips_softc *sc)
+{
+}
+
+int
+ips_copperhead_intr(void *arg)
+{
+ return (0);
+}
+
+void
+ips_morpheus_exec(struct ips_softc *sc)
+{
+ IPS_WRITE_4(sc, IPS_MORPHEUS_IQPR, sc->sc_cmdm->dm_seg.ds_addr);
+}
+
+void
+ips_morpheus_inten(struct ips_softc *sc)
+{
+ u_int32_t reg;
+
+ reg =3D IPS_READ_4(sc, IPS_MORPHEUS_OIMR);
+ reg &=3D ~0x08;
+ IPS_WRITE_4(sc, IPS_MORPHEUS_OIMR, reg);
+}
+
+int
+ips_morpheus_intr(void *arg)
+{
+ struct ips_softc *sc =3D arg;
+ struct ccb *ccb;
+ struct scsipi_xfer *xs;
+ u_int32_t oisr, oqpr;
+ int gsc, id, s, rv =3D 0;
+
+ oisr =3D IPS_READ_4(sc, IPS_MORPHEUS_OISR);
+ DPRINTF(IPS_D_INTR, ("%s: intr, OISR 0x%08x\n",
+ sc->sc_dev.dv_xname, oisr));
+
+ if (!(oisr & IPS_MORPHEUS_OISR_CMD))
+ return (0);
+
+ while ((oqpr =3D IPS_READ_4(sc, IPS_MORPHEUS_OQPR)) !=3D 0xffffffff) {
+ DPRINTF(IPS_D_INTR, ("OQPR 0x%08x\n", oqpr));
+
+ gsc =3D IPS_MORPHEUS_OQPR_GSC(oqpr);
+ id =3D IPS_MORPHEUS_OQPR_ID(oqpr);
+
+ if (gsc !=3D IPS_MORPHEUS_GSC_NOERR &&
+ gsc !=3D IPS_MORPHEUS_GSC_RECOV) {
+ DPRINTF(IPS_D_ERR, ("%s: intr, error 0x%x",
+ sc->sc_dev.dv_xname, gsc));
+ DPRINTF(IPS_D_ERR, (", OISR 0x%08x, OQPR 0x%08x\n",
+ oisr, oqpr));
+ }
+
+ if (id >=3D sc->sc_ai.max_concurrent_cmds) {
+ DPRINTF(IPS_D_ERR, ("%s: intr, bogus id %d",
+ sc->sc_dev.dv_xname, id));
+ DPRINTF(IPS_D_ERR, (", OISR 0x%08x, OQPR 0x%08x\n",
+ oisr, oqpr));
+ continue;
+ }
+
+ ccb =3D &sc->sc_ccb[id];
+ if (!(ccb->c_flags & CCB_F_RUN)) {
+ DPRINTF(IPS_D_ERR, ("%s: intr, ccb id %d not run",
+ sc->sc_dev.dv_xname, id));
+ DPRINTF(IPS_D_ERR, (", OISR 0x%08x, OQPR 0x%08x\n",
+ oisr, oqpr));
+ continue;
+ }
+
+ rv =3D 1;
+ bus_dmamap_unload(sc->sc_dmat, ccb->c_dmam);
+ xs =3D ccb->c_xfer;
+ xs->resid =3D 0;
+ xs->xs_status |=3D XS_STS_DONE;
+ callout_stop(&xs->xs_callout);
+ s =3D splbio();
+ scsipi_done(xs);
+ ccb->c_flags &=3D ~CCB_F_RUN;
+ TAILQ_INSERT_TAIL(&sc->sc_ccbq, ccb, c_link);
+ splx(s);
+ }
+
+ return (rv);
+}
+
+struct ccb *
+ips_ccb_alloc(bus_dma_tag_t dmat, int n)
+{
+ struct ccb *ccb;
+ int i;
+
+ if ((ccb =3D malloc(n * sizeof(*ccb), M_DEVBUF, M_NOWAIT)) =3D=3D NULL)
+ return (NULL);
+ bzero(ccb, n * sizeof(*ccb));
+
+ for (i =3D 0; i < n; i++) {
+ ccb[i].c_id =3D i;
+ if (bus_dmamap_create(dmat, IPS_MAXFER, IPS_MAXSGS,
+ IPS_MAXFER, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
+ &ccb[i].c_dmam))
+ goto fail;
+ }
+
+ return (ccb);
+fail:
+ for (; i > 0; i--)
+ bus_dmamap_destroy(dmat, ccb[i - 1].c_dmam);
+ free(ccb, M_DEVBUF);
+ return (NULL);
+}
+
+void
+ips_ccb_free(struct ccb *ccb, bus_dma_tag_t dmat, int n)
+{
+ int i;
+
+ for (i =3D 0; i < n; i++)
+ bus_dmamap_destroy(dmat, ccb[i - 1].c_dmam);
+ free(ccb, M_DEVBUF);
+}
+
+struct dmamem *
+ips_dmamem_alloc(bus_dma_tag_t tag, bus_size_t size)
+{
+ struct dmamem *dm;
+ int nsegs;
+
+ if ((dm =3D malloc(sizeof(*dm), M_DEVBUF, M_NOWAIT)) =3D=3D NULL)
+ return (NULL);
+
+ dm->dm_tag =3D tag;
+ dm->dm_size =3D size;
+
+ if (bus_dmamap_create(tag, size, 1, size, 0,
+ BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &dm->dm_map))
+ goto fail1;
+ if (bus_dmamem_alloc(tag, size, 0, 0, &dm->dm_seg, 1, &nsegs,
+ BUS_DMA_NOWAIT))
+ goto fail2;
+ if (bus_dmamem_map(tag, &dm->dm_seg, 1, size, (caddr_t *)&dm->dm_kva,
+ BUS_DMA_NOWAIT))
+ goto fail3;
+ bzero(dm->dm_kva, size);
+ if (bus_dmamap_load(tag, dm->dm_map, dm->dm_kva, size, NULL,
+ BUS_DMA_NOWAIT))
+ goto fail4;
+
+ return (dm);
+
+fail4:
+ bus_dmamem_unmap(tag, dm->dm_kva, size);
+fail3:
+ bus_dmamem_free(tag, &dm->dm_seg, 1);
+fail2:
+ bus_dmamap_destroy(tag, dm->dm_map);
+fail1:
+ free(dm, M_DEVBUF);
+ return (NULL);
+}
+
+void
+ips_dmamem_free(struct dmamem *dm)
+{
+ bus_dmamap_unload(dm->dm_tag, dm->dm_map);
+ bus_dmamem_unmap(dm->dm_tag, dm->dm_kva, dm->dm_size);
+ bus_dmamem_free(dm->dm_tag, &dm->dm_seg, 1);
+ bus_dmamap_destroy(dm->dm_tag, dm->dm_map);
+ free(dm, M_DEVBUF);
+}
Index: dev/pci/pcidevs
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/sys/dev/pci/pcidevs,v
retrieving revision 1.855.2.4
diff -u -r1.855.2.4 pcidevs
--- dev/pci/pcidevs 21 Feb 2007 13:17:59 -0000 1.855.2.4
+++ dev/pci/pcidevs 15 May 2007 02:00:26 -0000
@@ -820,6 +820,8 @@
/* XXX guess */
product ADP2 PERC_3QC 0x1365 Dell PERC 3/QC
=20
+product ADP2 SERVERAID 0x0250 ADP2 ServeRAID
+
/* Addtron Products */
product ADDTRON 8139 0x1360 8139 Ethernet
product ADDTRON RHINEII 0x1320 Rhine II 10/100 Ethernet
Index: dev/pci/pcidevs.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/sys/dev/pci/pcidevs.h,v
retrieving revision 1.854.2.4
diff -u -r1.854.2.4 pcidevs.h
--- dev/pci/pcidevs.h 21 Feb 2007 13:18:47 -0000 1.854.2.4
+++ dev/pci/pcidevs.h 15 May 2007 02:00:27 -0000
@@ -1,4 +1,4 @@
-/* $NetBSD: pcidevs.h,v 1.854.2.4 2007/02/21 13:18:47 tron Exp $ */
+/* $NetBSD$ */
=20
/*
* THIS FILE AUTOMATICALLY GENERATED. DO NOT EDIT.
@@ -827,6 +827,8 @@
/* XXX guess */
#define PCI_PRODUCT_ADP2_PERC_3QC 0x1365 /* Dell PERC 3/QC */
=20
+#define PCI_PRODUCT_ADP2_SERVERAID 0x0250 /* ADP2 ServeRAID */
+
/* Addtron Products */
#define PCI_PRODUCT_ADDTRON_8139 0x1360 /* 8139 Ethernet */
#define PCI_PRODUCT_ADDTRON_RHINEII 0x1320 /* Rhine II 10/100 Ethernet */
Index: dev/pci/pcidevs_data.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/sys/dev/pci/pcidevs_data.h,v
retrieving revision 1.853.2.4
diff -u -r1.853.2.4 pcidevs_data.h
--- dev/pci/pcidevs_data.h 21 Feb 2007 13:18:48 -0000 1.853.2.4
+++ dev/pci/pcidevs_data.h 15 May 2007 02:00:28 -0000
@@ -1,4 +1,4 @@
-/* $NetBSD: pcidevs_data.h,v 1.853.2.4 2007/02/21 13:18:48 tron Exp $ */
+/* $NetBSD$ */
=20
/*
* THIS FILE AUTOMATICALLY GENERATED. DO NOT EDIT.
@@ -3008,6 +3008,10 @@
"Dell PERC 3/QC",
},
{
+ PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_SERVERAID,
+ "ADP2 ServeRAID",
+ },
+ {
PCI_VENDOR_ADDTRON, PCI_PRODUCT_ADDTRON_8139,
"8139 Ethernet",
},
@@ -12708,4 +12712,4 @@
"Video Controller",
},
};
-const int pci_nproducts =3D 2583;
+const int pci_nproducts =3D 2584;
Index: dev/scsipi/scsipi_all.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/sys/dev/scsipi/scsipi_all.h,v
retrieving revision 1.32
diff -u -r1.32 scsipi_all.h
--- dev/scsipi/scsipi_all.h 1 Dec 2006 21:36:56 -0000 1.32
+++ dev/scsipi/scsipi_all.h 15 May 2007 02:00:28 -0000
@@ -55,6 +55,8 @@
* Some basic, common SCSI commands
*/
=20
+#define TEST_UNIT_READY 0x00
+#define REQUEST_SENSE 0x03
#define INQUIRY 0x12
struct scsipi_inquiry {
u_int8_t opcode;
--WIyZ46R2i8wDzkSu--
--rJwd6BRFiFCcLxzm
Content-Type: application/pgp-signature
Content-Disposition: inline
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (NetBSD)
iQIVAwUBRkoIQe1mMGan/TnWAQJ1ig//R2RC4PBPILSK215RxTXXRZFY7C/ybxFV
Zosby6Z6ttzk/x+jiwGFl0WuALfJvTt7XUHuFNmx7kvybjf6V26lpcJxnsxnb6qW
mWC5XF8LuLj5MctNbpfAo+ip4/lE5iHrWvN4DXGlKb4bXwDT7Rew9J0AaMcHRwTN
YpIq2lLh3n1hVMlK4P2hHlm3KGFD9r4yPusW3HGcmIznVxYLHvV6P01Wv476OfBm
1hBrO+1W+WR92drKznQPcAtmwNpUlTqnvcStFRDpEYfuIPJrlWe5s3DtZHY7vzyf
tXgGvLJqbmGo27lVMnKIS0XVtkFImlQj/WnKxIhijpo7vgmsshOeiWYIrCpQMKfo
F3GtaSlvovVs9e4D6eQ00tSQ8t4vwQxoXdAc4aq8TwjVF4RoZ3zhdHP4qiN8yiUY
qE03XV/4pha1wIQooKuuwK6dC3i9LTQIsuSdeoBQAxQzj3OIx8DxJQof8NVsO+ao
Fm3dIFgpZRWyRAl8EsNH+uM4el2vi+uTti0JdikvT7e+z3jkR//2CNgsgeYJRZ6H
rgGby3TAA03K+u8sc+QRRrwFTaBID9P11GFtmCMGKgh76fgbNWG14o8auQALVJC3
K1l7wybEy93UCjyiXcqFZmqZRLkufOaUVdxh0mSzE1EKnFYaBsUPSpaCPejpaUSW
WZdM+x/eq4Q=
=DDkf
-----END PGP SIGNATURE-----
--rJwd6BRFiFCcLxzm--