[BACK]Return to arc.c CVS log [TXT][DIR] Up to [local] / sys / dev / pci

Annotation of sys/dev/pci/arc.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: arc.c,v 1.65 2007/07/11 19:01:30 otto Exp $ */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 2006 David Gwynne <dlg@openbsd.org>
        !             5:  *
        !             6:  * Permission to use, copy, modify, and distribute this software for any
        !             7:  * purpose with or without fee is hereby granted, provided that the above
        !             8:  * copyright notice and this permission notice appear in all copies.
        !             9:  *
        !            10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
        !            11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
        !            13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            14:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
        !            15:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
        !            16:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            17:  */
        !            18:
        !            19: #include "bio.h"
        !            20:
        !            21: #include <sys/param.h>
        !            22: #include <sys/systm.h>
        !            23: #include <sys/buf.h>
        !            24: #include <sys/kernel.h>
        !            25: #include <sys/malloc.h>
        !            26: #include <sys/device.h>
        !            27: #include <sys/proc.h>
        !            28: #include <sys/rwlock.h>
        !            29:
        !            30: #include <machine/bus.h>
        !            31:
        !            32: #include <dev/pci/pcireg.h>
        !            33: #include <dev/pci/pcivar.h>
        !            34: #include <dev/pci/pcidevs.h>
        !            35:
        !            36: #include <scsi/scsi_all.h>
        !            37: #include <scsi/scsiconf.h>
        !            38:
        !            39: #include <sys/sensors.h>
        !            40: #if NBIO > 0
        !            41: #include <sys/ioctl.h>
        !            42: #include <dev/biovar.h>
        !            43: #endif
        !            44:
        !            45: #ifdef ARC_DEBUG
        !            46: #define ARC_D_INIT     (1<<0)
        !            47: #define ARC_D_RW       (1<<1)
        !            48: #define ARC_D_DB       (1<<2)
        !            49:
        !            50: int arcdebug = 0;
        !            51:
        !            52: #define DPRINTF(p...)          do { if (arcdebug) printf(p); } while (0)
        !            53: #define DNPRINTF(n, p...)      do { if ((n) & arcdebug) printf(p); } while (0)
        !            54:
        !            55: #else
        !            56: #define DPRINTF(p...)          /* p */
        !            57: #define DNPRINTF(n, p...)      /* n, p */
        !            58: #endif
        !            59:
        !            60: static const struct pci_matchid arc_devices[] = {
        !            61:        { PCI_VENDOR_ARECA,     PCI_PRODUCT_ARECA_ARC1110 },
        !            62:        { PCI_VENDOR_ARECA,     PCI_PRODUCT_ARECA_ARC1120 },
        !            63:        { PCI_VENDOR_ARECA,     PCI_PRODUCT_ARECA_ARC1130 },
        !            64:        { PCI_VENDOR_ARECA,     PCI_PRODUCT_ARECA_ARC1160 },
        !            65:        { PCI_VENDOR_ARECA,     PCI_PRODUCT_ARECA_ARC1170 },
        !            66:        { PCI_VENDOR_ARECA,     PCI_PRODUCT_ARECA_ARC1210 },
        !            67:        { PCI_VENDOR_ARECA,     PCI_PRODUCT_ARECA_ARC1220 },
        !            68:        { PCI_VENDOR_ARECA,     PCI_PRODUCT_ARECA_ARC1230 },
        !            69:        { PCI_VENDOR_ARECA,     PCI_PRODUCT_ARECA_ARC1260 },
        !            70:        { PCI_VENDOR_ARECA,     PCI_PRODUCT_ARECA_ARC1270 },
        !            71:        { PCI_VENDOR_ARECA,     PCI_PRODUCT_ARECA_ARC1280 },
        !            72:        { PCI_VENDOR_ARECA,     PCI_PRODUCT_ARECA_ARC1380 },
        !            73:        { PCI_VENDOR_ARECA,     PCI_PRODUCT_ARECA_ARC1381 },
        !            74:        { PCI_VENDOR_ARECA,     PCI_PRODUCT_ARECA_ARC1680 },
        !            75:        { PCI_VENDOR_ARECA,     PCI_PRODUCT_ARECA_ARC1681 }
        !            76: };
        !            77:
        !            78: #define ARC_PCI_BAR                    PCI_MAPREG_START
        !            79:
        !            80: #define ARC_REG_INB_MSG0               0x0010
        !            81: #define  ARC_REG_INB_MSG0_NOP                  (0x00000000)
        !            82: #define  ARC_REG_INB_MSG0_GET_CONFIG           (0x00000001)
        !            83: #define  ARC_REG_INB_MSG0_SET_CONFIG           (0x00000002)
        !            84: #define  ARC_REG_INB_MSG0_ABORT_CMD            (0x00000003)
        !            85: #define  ARC_REG_INB_MSG0_STOP_BGRB            (0x00000004)
        !            86: #define  ARC_REG_INB_MSG0_FLUSH_CACHE          (0x00000005)
        !            87: #define  ARC_REG_INB_MSG0_START_BGRB           (0x00000006)
        !            88: #define  ARC_REG_INB_MSG0_CHK331PENDING                (0x00000007)
        !            89: #define  ARC_REG_INB_MSG0_SYNC_TIMER           (0x00000008)
        !            90: #define ARC_REG_INB_MSG1               0x0014
        !            91: #define ARC_REG_OUTB_ADDR0             0x0018
        !            92: #define ARC_REG_OUTB_ADDR1             0x001c
        !            93: #define  ARC_REG_OUTB_ADDR1_FIRMWARE_OK                (1<<31)
        !            94: #define ARC_REG_INB_DOORBELL           0x0020
        !            95: #define  ARC_REG_INB_DOORBELL_WRITE_OK         (1<<0)
        !            96: #define  ARC_REG_INB_DOORBELL_READ_OK          (1<<1)
        !            97: #define ARC_REG_OUTB_DOORBELL          0x002c
        !            98: #define  ARC_REG_OUTB_DOORBELL_WRITE_OK                (1<<0)
        !            99: #define  ARC_REG_OUTB_DOORBELL_READ_OK         (1<<1)
        !           100: #define ARC_REG_INTRSTAT               0x0030
        !           101: #define  ARC_REG_INTRSTAT_MSG0                 (1<<0)
        !           102: #define  ARC_REG_INTRSTAT_MSG1                 (1<<1)
        !           103: #define  ARC_REG_INTRSTAT_DOORBELL             (1<<2)
        !           104: #define  ARC_REG_INTRSTAT_POSTQUEUE            (1<<3)
        !           105: #define  ARC_REG_INTRSTAT_PCI                  (1<<4)
        !           106: #define ARC_REG_INTRMASK               0x0034
        !           107: #define  ARC_REG_INTRMASK_MSG0                 (1<<0)
        !           108: #define  ARC_REG_INTRMASK_MSG1                 (1<<1)
        !           109: #define  ARC_REG_INTRMASK_DOORBELL             (1<<2)
        !           110: #define  ARC_REG_INTRMASK_POSTQUEUE            (1<<3)
        !           111: #define  ARC_REG_INTRMASK_PCI                  (1<<4)
        !           112: #define ARC_REG_POST_QUEUE             0x0040
        !           113: #define  ARC_REG_POST_QUEUE_ADDR_SHIFT         5
        !           114: #define  ARC_REG_POST_QUEUE_IAMBIOS            (1<<30)
        !           115: #define  ARC_REG_POST_QUEUE_BIGFRAME           (1<<31)
        !           116: #define ARC_REG_REPLY_QUEUE            0x0044
        !           117: #define  ARC_REG_REPLY_QUEUE_ADDR_SHIFT                5
        !           118: #define  ARC_REG_REPLY_QUEUE_ERR               (1<<28)
        !           119: #define  ARC_REG_REPLY_QUEUE_IAMBIOS           (1<<30)
        !           120: #define ARC_REG_MSGBUF                 0x0a00
        !           121: #define  ARC_REG_MSGBUF_LEN            1024
        !           122: #define ARC_REG_IOC_WBUF_LEN           0x0e00
        !           123: #define ARC_REG_IOC_WBUF               0x0e04
        !           124: #define ARC_REG_IOC_RBUF_LEN           0x0f00
        !           125: #define ARC_REG_IOC_RBUF               0x0f04
        !           126: #define  ARC_REG_IOC_RWBUF_MAXLEN      124 /* for both RBUF and WBUF */
        !           127:
        !           128: struct arc_msg_firmware_info {
        !           129:        u_int32_t               signature;
        !           130: #define ARC_FWINFO_SIGNATURE_GET_CONFIG                (0x87974060)
        !           131:        u_int32_t               request_len;
        !           132:        u_int32_t               queue_len;
        !           133:        u_int32_t               sdram_size;
        !           134:        u_int32_t               sata_ports;
        !           135:        u_int8_t                vendor[40];
        !           136:        u_int8_t                model[8];
        !           137:        u_int8_t                fw_version[16];
        !           138:        u_int8_t                device_map[16];
        !           139: } __packed;
        !           140:
        !           141: struct arc_msg_scsicmd {
        !           142:        u_int8_t                bus;
        !           143:        u_int8_t                target;
        !           144:        u_int8_t                lun;
        !           145:        u_int8_t                function;
        !           146:
        !           147:        u_int8_t                cdb_len;
        !           148:        u_int8_t                sgl_len;
        !           149:        u_int8_t                flags;
        !           150: #define ARC_MSG_SCSICMD_FLAG_SGL_BSIZE_512     (1<<0)
        !           151: #define ARC_MSG_SCSICMD_FLAG_FROM_BIOS         (1<<1)
        !           152: #define ARC_MSG_SCSICMD_FLAG_WRITE             (1<<2)
        !           153: #define ARC_MSG_SCSICMD_FLAG_SIMPLEQ           (0x00)
        !           154: #define ARC_MSG_SCSICMD_FLAG_HEADQ             (0x08)
        !           155: #define ARC_MSG_SCSICMD_FLAG_ORDERQ            (0x10)
        !           156:        u_int8_t                reserved;
        !           157:
        !           158:        u_int32_t               context;
        !           159:        u_int32_t               data_len;
        !           160:
        !           161: #define ARC_MSG_CDBLEN                         16
        !           162:        u_int8_t                cdb[ARC_MSG_CDBLEN];
        !           163:
        !           164:        u_int8_t                status;
        !           165: #define ARC_MSG_STATUS_SELTIMEOUT              0xf0
        !           166: #define ARC_MSG_STATUS_ABORTED                 0xf1
        !           167: #define ARC_MSG_STATUS_INIT_FAIL               0xf2
        !           168: #define ARC_MSG_SENSELEN                       15
        !           169:        u_int8_t                sense_data[ARC_MSG_SENSELEN];
        !           170:
        !           171:        /* followed by an sgl */
        !           172: } __packed;
        !           173:
        !           174: struct arc_sge {
        !           175:        u_int32_t               sg_hdr;
        !           176: #define ARC_SGE_64BIT                          (1<<24)
        !           177:        u_int32_t               sg_lo_addr;
        !           178:        u_int32_t               sg_hi_addr;
        !           179: } __packed;
        !           180:
        !           181: #define ARC_MAX_TARGET         16
        !           182: #define ARC_MAX_LUN            8
        !           183: #define ARC_MAX_IOCMDLEN       512
        !           184: #define ARC_BLOCKSIZE          512
        !           185:
        !           186: /* the firmware deals with up to 256 or 512 byte command frames. */
        !           187: /* sizeof(struct arc_msg_scsicmd) + (sizeof(struct arc_sge) * 38) == 508 */
        !           188: #define ARC_SGL_MAXLEN         38
        !           189: /* sizeof(struct arc_msg_scsicmd) + (sizeof(struct arc_sge) * 17) == 252 */
        !           190: #define ARC_SGL_256LEN         17
        !           191:
        !           192: struct arc_io_cmd {
        !           193:        struct arc_msg_scsicmd  cmd;
        !           194:        struct arc_sge          sgl[ARC_SGL_MAXLEN];
        !           195: } __packed;
        !           196:
        !           197: /* definitions of the firmware commands sent via the doorbells */
        !           198:
        !           199: struct arc_fw_hdr {
        !           200:        u_int8_t                byte1;
        !           201:        u_int8_t                byte2;
        !           202:        u_int8_t                byte3;
        !           203: } __packed;
        !           204:
        !           205: /* the fw header must always equal this */
        !           206: struct arc_fw_hdr arc_fw_hdr = { 0x5e, 0x01, 0x61 };
        !           207:
        !           208: struct arc_fw_bufhdr {
        !           209:        struct arc_fw_hdr       hdr;
        !           210:        u_int16_t               len;
        !           211: } __packed;
        !           212:
        !           213: #define ARC_FW_RAIDINFO                0x20    /* opcode + raid# */
        !           214: #define ARC_FW_VOLINFO         0x21    /* opcode + vol# */
        !           215: #define ARC_FW_DISKINFO                0x22    /* opcode + physdisk# */
        !           216: #define ARC_FW_SYSINFO         0x23    /* opcode. reply is fw_sysinfo */
        !           217: #define ARC_FW_MUTE_ALARM      0x30    /* opcode only */
        !           218: #define ARC_FW_SET_ALARM       0x31    /* opcode + 1 byte for setting */
        !           219: #define  ARC_FW_SET_ALARM_DISABLE              0x00
        !           220: #define  ARC_FW_SET_ALARM_ENABLE               0x01
        !           221: #define ARC_FW_NOP             0x38    /* opcode only */
        !           222:
        !           223: #define ARC_FW_CMD_OK          0x41
        !           224:
        !           225: struct arc_fw_comminfo {
        !           226:        u_int8_t                baud_rate;
        !           227:        u_int8_t                data_bits;
        !           228:        u_int8_t                stop_bits;
        !           229:        u_int8_t                parity;
        !           230:        u_int8_t                flow_control;
        !           231: } __packed;
        !           232:
        !           233: struct arc_fw_scsiattr {
        !           234:        u_int8_t                channel;// channel for SCSI target (0/1)
        !           235:        u_int8_t                target;
        !           236:        u_int8_t                lun;
        !           237:        u_int8_t                tagged;
        !           238:        u_int8_t                cache;
        !           239:        u_int8_t                speed;
        !           240: } __packed;
        !           241:
        !           242: struct arc_fw_raidinfo {
        !           243:        u_int8_t                set_name[16];
        !           244:        u_int32_t               capacity;
        !           245:        u_int32_t               capacity2;
        !           246:        u_int32_t               fail_mask;
        !           247:        u_int8_t                device_array[32];
        !           248:        u_int8_t                member_devices;
        !           249:        u_int8_t                new_member_devices;
        !           250:        u_int8_t                raid_state;
        !           251:        u_int8_t                volumes;
        !           252:        u_int8_t                volume_list[16];
        !           253:        u_int8_t                reserved1[3];
        !           254:        u_int8_t                free_segments;
        !           255:        u_int32_t               raw_stripes[8];
        !           256:        u_int8_t                reserved2[12];
        !           257: } __packed;
        !           258:
        !           259: struct arc_fw_volinfo {
        !           260:        u_int8_t                set_name[16];
        !           261:        u_int32_t               capacity;
        !           262:        u_int32_t               capacity2;
        !           263:        u_int32_t               fail_mask;
        !           264:        u_int32_t               stripe_size; /* in blocks */
        !           265:        u_int32_t               new_fail_mask;
        !           266:        u_int32_t               new_stripe_size;
        !           267:        u_int32_t               volume_status;
        !           268: #define ARC_FW_VOL_STATUS_NORMAL       0x00
        !           269: #define ARC_FW_VOL_STATUS_INITTING     (1<<0)
        !           270: #define ARC_FW_VOL_STATUS_FAILED       (1<<1)
        !           271: #define ARC_FW_VOL_STATUS_MIGRATING    (1<<2)
        !           272: #define ARC_FW_VOL_STATUS_REBUILDING   (1<<3)
        !           273: #define ARC_FW_VOL_STATUS_NEED_INIT    (1<<4)
        !           274: #define ARC_FW_VOL_STATUS_NEED_MIGRATE (1<<5)
        !           275: #define ARC_FW_VOL_STATUS_INIT_FLAG    (1<<6)
        !           276: #define ARC_FW_VOL_STATUS_NEED_REGEN   (1<<7)
        !           277: #define ARC_FW_VOL_STATUS_CHECKING     (1<<8)
        !           278: #define ARC_FW_VOL_STATUS_NEED_CHECK   (1<<9)
        !           279:        u_int32_t               progress;
        !           280:        struct arc_fw_scsiattr  scsi_attr;
        !           281:        u_int8_t                member_disks;
        !           282:        u_int8_t                raid_level;
        !           283: #define ARC_FW_VOL_RAIDLEVEL_0         0x00
        !           284: #define ARC_FW_VOL_RAIDLEVEL_1         0x01
        !           285: #define ARC_FW_VOL_RAIDLEVEL_3         0x02
        !           286: #define ARC_FW_VOL_RAIDLEVEL_5         0x03
        !           287: #define ARC_FW_VOL_RAIDLEVEL_6         0x04
        !           288: #define ARC_FW_VOL_RAIDLEVEL_PASSTHRU  0x05
        !           289:        u_int8_t                new_member_disks;
        !           290:        u_int8_t                new_raid_level;
        !           291:        u_int8_t                raid_set_number;
        !           292:        u_int8_t                reserved[5];
        !           293: } __packed;
        !           294:
        !           295: struct arc_fw_diskinfo {
        !           296:        u_int8_t                model[40];
        !           297:        u_int8_t                serial[20];
        !           298:        u_int8_t                firmware_rev[8];
        !           299:        u_int32_t               capacity;
        !           300:        u_int32_t               capacity2;
        !           301:        u_int8_t                device_state;
        !           302:        u_int8_t                pio_mode;
        !           303:        u_int8_t                current_udma_mode;
        !           304:        u_int8_t                udma_mode;
        !           305:        u_int8_t                drive_select;
        !           306:        u_int8_t                raid_number; // 0xff unowned
        !           307:        struct arc_fw_scsiattr  scsi_attr;
        !           308:        u_int8_t                reserved[40];
        !           309: } __packed;
        !           310:
        !           311: struct arc_fw_sysinfo {
        !           312:        u_int8_t                vendor_name[40];
        !           313:        u_int8_t                serial_number[16];
        !           314:        u_int8_t                firmware_version[16];
        !           315:        u_int8_t                boot_version[16];
        !           316:        u_int8_t                mb_version[16];
        !           317:        u_int8_t                model_name[8];
        !           318:
        !           319:        u_int8_t                local_ip[4];
        !           320:        u_int8_t                current_ip[4];
        !           321:
        !           322:        u_int32_t               time_tick;
        !           323:        u_int32_t               cpu_speed;
        !           324:        u_int32_t               icache;
        !           325:        u_int32_t               dcache;
        !           326:        u_int32_t               scache;
        !           327:        u_int32_t               memory_size;
        !           328:        u_int32_t               memory_speed;
        !           329:        u_int32_t               events;
        !           330:
        !           331:        u_int8_t                gsiMacAddress[6];
        !           332:        u_int8_t                gsiDhcp;
        !           333:
        !           334:        u_int8_t                alarm;
        !           335:        u_int8_t                channel_usage;
        !           336:        u_int8_t                max_ata_mode;
        !           337:        u_int8_t                sdram_ecc;
        !           338:        u_int8_t                rebuild_priority;
        !           339:        struct arc_fw_comminfo  comm_a;
        !           340:        struct arc_fw_comminfo  comm_b;
        !           341:        u_int8_t                ide_channels;
        !           342:        u_int8_t                scsi_host_channels;
        !           343:        u_int8_t                ide_host_channels;
        !           344:        u_int8_t                max_volume_set;
        !           345:        u_int8_t                max_raid_set;
        !           346:        u_int8_t                ether_port;
        !           347:        u_int8_t                raid6_engine;
        !           348:        u_int8_t                reserved[75];
        !           349: } __packed;
        !           350:
        !           351: int                    arc_match(struct device *, void *, void *);
        !           352: void                   arc_attach(struct device *, struct device *, void *);
        !           353: int                    arc_detach(struct device *, int);
        !           354: void                   arc_shutdown(void *);
        !           355: int                    arc_intr(void *);
        !           356:
        !           357: struct arc_ccb;
        !           358: TAILQ_HEAD(arc_ccb_list, arc_ccb);
        !           359:
        !           360: struct arc_softc {
        !           361:        struct device           sc_dev;
        !           362:        struct scsi_link        sc_link;
        !           363:
        !           364:        pci_chipset_tag_t       sc_pc;
        !           365:        pcitag_t                sc_tag;
        !           366:
        !           367:        bus_space_tag_t         sc_iot;
        !           368:        bus_space_handle_t      sc_ioh;
        !           369:        bus_size_t              sc_ios;
        !           370:        bus_dma_tag_t           sc_dmat;
        !           371:
        !           372:        void                    *sc_ih;
        !           373:
        !           374:        void                    *sc_shutdownhook;
        !           375:
        !           376:        int                     sc_req_count;
        !           377:
        !           378:        struct arc_dmamem       *sc_requests;
        !           379:        struct arc_ccb          *sc_ccbs;
        !           380:        struct arc_ccb_list     sc_ccb_free;
        !           381:
        !           382:        struct scsibus_softc    *sc_scsibus;
        !           383:
        !           384:        struct rwlock           sc_lock;
        !           385:        volatile int            sc_talking;
        !           386:
        !           387:        struct ksensor          *sc_sensors;
        !           388:        struct ksensordev       sc_sensordev;
        !           389:        int                     sc_nsensors;
        !           390: };
        !           391: #define DEVNAME(_s)            ((_s)->sc_dev.dv_xname)
        !           392:
        !           393: struct cfattach arc_ca = {
        !           394:        sizeof(struct arc_softc), arc_match, arc_attach, arc_detach
        !           395: };
        !           396:
        !           397: struct cfdriver arc_cd = {
        !           398:        NULL, "arc", DV_DULL
        !           399: };
        !           400:
        !           401: /* interface for scsi midlayer to talk to */
        !           402: int                    arc_scsi_cmd(struct scsi_xfer *);
        !           403: void                   arc_minphys(struct buf *);
        !           404:
        !           405: struct scsi_adapter arc_switch = {
        !           406:        arc_scsi_cmd, arc_minphys, NULL, NULL, NULL
        !           407: };
        !           408:
        !           409: struct scsi_device arc_dev = {
        !           410:        NULL, NULL, NULL, NULL
        !           411: };
        !           412:
        !           413: /* code to deal with getting bits in and out of the bus space */
        !           414: u_int32_t              arc_read(struct arc_softc *, bus_size_t);
        !           415: void                   arc_read_region(struct arc_softc *, bus_size_t,
        !           416:                            void *, size_t);
        !           417: void                   arc_write(struct arc_softc *, bus_size_t, u_int32_t);
        !           418: void                   arc_write_region(struct arc_softc *, bus_size_t,
        !           419:                            void *, size_t);
        !           420: int                    arc_wait_eq(struct arc_softc *, bus_size_t,
        !           421:                            u_int32_t, u_int32_t);
        !           422: int                    arc_wait_ne(struct arc_softc *, bus_size_t,
        !           423:                            u_int32_t, u_int32_t);
        !           424: int                    arc_msg0(struct arc_softc *, u_int32_t);
        !           425:
        !           426: #define arc_push(_s, _r)       arc_write((_s), ARC_REG_POST_QUEUE, (_r))
        !           427: #define arc_pop(_s)            arc_read((_s), ARC_REG_REPLY_QUEUE)
        !           428:
        !           429: /* wrap up the bus_dma api */
        !           430: struct arc_dmamem {
        !           431:        bus_dmamap_t            adm_map;
        !           432:        bus_dma_segment_t       adm_seg;
        !           433:        size_t                  adm_size;
        !           434:        caddr_t                 adm_kva;
        !           435: };
        !           436: #define ARC_DMA_MAP(_adm)      ((_adm)->adm_map)
        !           437: #define ARC_DMA_DVA(_adm)      ((_adm)->adm_map->dm_segs[0].ds_addr)
        !           438: #define ARC_DMA_KVA(_adm)      ((void *)(_adm)->adm_kva)
        !           439:
        !           440: struct arc_dmamem      *arc_dmamem_alloc(struct arc_softc *, size_t);
        !           441: void                   arc_dmamem_free(struct arc_softc *,
        !           442:                            struct arc_dmamem *);
        !           443:
        !           444: /* stuff to manage a scsi command */
        !           445: struct arc_ccb {
        !           446:        struct arc_softc        *ccb_sc;
        !           447:        int                     ccb_id;
        !           448:
        !           449:        struct scsi_xfer        *ccb_xs;
        !           450:
        !           451:        bus_dmamap_t            ccb_dmamap;
        !           452:        bus_addr_t              ccb_offset;
        !           453:        struct arc_io_cmd       *ccb_cmd;
        !           454:        u_int32_t               ccb_cmd_post;
        !           455:
        !           456:        TAILQ_ENTRY(arc_ccb)    ccb_link;
        !           457: };
        !           458:
        !           459: int                    arc_alloc_ccbs(struct arc_softc *);
        !           460: struct arc_ccb         *arc_get_ccb(struct arc_softc *);
        !           461: void                   arc_put_ccb(struct arc_softc *, struct arc_ccb *);
        !           462: int                    arc_load_xs(struct arc_ccb *);
        !           463: int                    arc_complete(struct arc_softc *, struct arc_ccb *,
        !           464:                            int);
        !           465: void                   arc_scsi_cmd_done(struct arc_softc *, struct arc_ccb *,
        !           466:                            u_int32_t);
        !           467:
        !           468: /* real stuff for dealing with the hardware */
        !           469: int                    arc_map_pci_resources(struct arc_softc *,
        !           470:                            struct pci_attach_args *);
        !           471: int                    arc_query_firmware(struct arc_softc *);
        !           472:
        !           473:
        !           474: #if NBIO > 0
        !           475: /* stuff to do messaging via the doorbells */
        !           476: void                   arc_lock(struct arc_softc *);
        !           477: void                   arc_unlock(struct arc_softc *);
        !           478: void                   arc_wait(struct arc_softc *);
        !           479: u_int8_t               arc_msg_cksum(void *, u_int16_t);
        !           480: int                    arc_msgbuf(struct arc_softc *, void *, size_t,
        !           481:                            void *, size_t);
        !           482:
        !           483: /* bioctl */
        !           484: int                    arc_bioctl(struct device *, u_long, caddr_t);
        !           485: int                    arc_bio_inq(struct arc_softc *, struct bioc_inq *);
        !           486: int                    arc_bio_vol(struct arc_softc *, struct bioc_vol *);
        !           487: int                    arc_bio_disk(struct arc_softc *, struct bioc_disk *);
        !           488: int                    arc_bio_alarm(struct arc_softc *, struct bioc_alarm *);
        !           489: int                    arc_bio_alarm_state(struct arc_softc *,
        !           490:                            struct bioc_alarm *);
        !           491:
        !           492: int                    arc_bio_getvol(struct arc_softc *, int,
        !           493:                            struct arc_fw_volinfo *);
        !           494:
        !           495: #ifndef SMALL_KERNEL
        !           496: /* sensors */
        !           497: void                   arc_create_sensors(void *, void *);
        !           498: void                   arc_refresh_sensors(void *);
        !           499: #endif /* SMALL_KERNEL */
        !           500: #endif
        !           501:
        !           502: int
        !           503: arc_match(struct device *parent, void *match, void *aux)
        !           504: {
        !           505:        return (pci_matchbyid((struct pci_attach_args *)aux, arc_devices,
        !           506:            sizeof(arc_devices) / sizeof(arc_devices[0])));
        !           507: }
        !           508:
        !           509: void
        !           510: arc_attach(struct device *parent, struct device *self, void *aux)
        !           511: {
        !           512:        struct arc_softc                *sc = (struct arc_softc *)self;
        !           513:        struct pci_attach_args          *pa = aux;
        !           514:        struct scsibus_attach_args      saa;
        !           515:        struct device                   *child;
        !           516:
        !           517:        sc->sc_talking = 0;
        !           518:        rw_init(&sc->sc_lock, "arcmsg");
        !           519:
        !           520:        if (arc_map_pci_resources(sc, pa) != 0) {
        !           521:                /* error message printed by arc_map_pci_resources */
        !           522:                return;
        !           523:        }
        !           524:
        !           525:        if (arc_query_firmware(sc) != 0) {
        !           526:                /* error message printed by arc_query_firmware */
        !           527:                return;
        !           528:        }
        !           529:
        !           530:        if (arc_alloc_ccbs(sc) != 0) {
        !           531:                /* error message printed by arc_alloc_ccbs */
        !           532:                return;
        !           533:        }
        !           534:
        !           535:        sc->sc_shutdownhook = shutdownhook_establish(arc_shutdown, sc);
        !           536:        if (sc->sc_shutdownhook == NULL)
        !           537:                panic("unable to establish arc powerhook");
        !           538:
        !           539:        sc->sc_link.device = &arc_dev;
        !           540:        sc->sc_link.adapter = &arc_switch;
        !           541:        sc->sc_link.adapter_softc = sc;
        !           542:        sc->sc_link.adapter_target = ARC_MAX_TARGET;
        !           543:        sc->sc_link.adapter_buswidth = ARC_MAX_TARGET;
        !           544:        sc->sc_link.openings = sc->sc_req_count / ARC_MAX_TARGET;
        !           545:
        !           546:        bzero(&saa, sizeof(saa));
        !           547:        saa.saa_sc_link = &sc->sc_link;
        !           548:
        !           549:        child = config_found(self, &saa, scsiprint);
        !           550:        sc->sc_scsibus = (struct scsibus_softc *)child;
        !           551:
        !           552:        /* enable interrupts */
        !           553:        arc_write(sc, ARC_REG_INTRMASK,
        !           554:            ~(ARC_REG_INTRMASK_POSTQUEUE|ARC_REG_INTRSTAT_DOORBELL));
        !           555:
        !           556: #if NBIO > 0
        !           557:        if (bio_register(self, arc_bioctl) != 0)
        !           558:                panic("%s: bioctl registration failed\n", DEVNAME(sc));
        !           559:
        !           560: #ifndef SMALL_KERNEL
        !           561:        /*
        !           562:         * you need to talk to the firmware to get volume info. our firmware
        !           563:         * interface relies on being able to sleep, so we need to use a thread
        !           564:         * to do the work.
        !           565:         */
        !           566:        if (scsi_task(arc_create_sensors, sc, NULL, 1) != 0)
        !           567:                printf("%s: unable to schedule arc_create_sensors as a "
        !           568:                    "scsi task", DEVNAME(sc));
        !           569: #endif
        !           570: #endif
        !           571:
        !           572:        return;
        !           573: }
        !           574:
        !           575: int
        !           576: arc_detach(struct device *self, int flags)
        !           577: {
        !           578:        struct arc_softc                *sc = (struct arc_softc *)self;
        !           579:
        !           580:        shutdownhook_disestablish(sc->sc_shutdownhook);
        !           581:
        !           582:        if (arc_msg0(sc, ARC_REG_INB_MSG0_STOP_BGRB) != 0)
        !           583:                printf("%s: timeout waiting to stop bg rebuild\n", DEVNAME(sc));
        !           584:
        !           585:        if (arc_msg0(sc, ARC_REG_INB_MSG0_FLUSH_CACHE) != 0)
        !           586:                printf("%s: timeout waiting to flush cache\n", DEVNAME(sc));
        !           587:
        !           588:        return (0);
        !           589: }
        !           590:
        !           591: void
        !           592: arc_shutdown(void *xsc)
        !           593: {
        !           594:        struct arc_softc                *sc = xsc;
        !           595:
        !           596:        if (arc_msg0(sc, ARC_REG_INB_MSG0_STOP_BGRB) != 0)
        !           597:                printf("%s: timeout waiting to stop bg rebuild\n", DEVNAME(sc));
        !           598:
        !           599:        if (arc_msg0(sc, ARC_REG_INB_MSG0_FLUSH_CACHE) != 0)
        !           600:                printf("%s: timeout waiting to flush cache\n", DEVNAME(sc));
        !           601: }
        !           602:
        !           603: int
        !           604: arc_intr(void *arg)
        !           605: {
        !           606:        struct arc_softc                *sc = arg;
        !           607:        struct arc_ccb                  *ccb = NULL;
        !           608:        char                            *kva = ARC_DMA_KVA(sc->sc_requests);
        !           609:        struct arc_io_cmd               *cmd;
        !           610:        u_int32_t                       reg, intrstat;
        !           611:
        !           612:        intrstat = arc_read(sc, ARC_REG_INTRSTAT);
        !           613:        if (intrstat == 0x0)
        !           614:                return (0);
        !           615:        intrstat &= ARC_REG_INTRSTAT_POSTQUEUE | ARC_REG_INTRSTAT_DOORBELL;
        !           616:        arc_write(sc, ARC_REG_INTRSTAT, intrstat);
        !           617:
        !           618:        if (intrstat & ARC_REG_INTRSTAT_DOORBELL) {
        !           619:                if (sc->sc_talking) {
        !           620:                        /* if an ioctl is talking, wake it up */
        !           621:                        arc_write(sc, ARC_REG_INTRMASK,
        !           622:                            ~ARC_REG_INTRMASK_POSTQUEUE);
        !           623:                        wakeup(sc);
        !           624:                } else {
        !           625:                        /* otherwise drop it */
        !           626:                        reg = arc_read(sc, ARC_REG_OUTB_DOORBELL);
        !           627:                        arc_write(sc, ARC_REG_OUTB_DOORBELL, reg);
        !           628:                        if (reg & ARC_REG_OUTB_DOORBELL_WRITE_OK)
        !           629:                                arc_write(sc, ARC_REG_INB_DOORBELL,
        !           630:                                    ARC_REG_INB_DOORBELL_READ_OK);
        !           631:                }
        !           632:        }
        !           633:
        !           634:        while ((reg = arc_pop(sc)) != 0xffffffff) {
        !           635:                cmd = (struct arc_io_cmd *)(kva +
        !           636:                    ((reg << ARC_REG_REPLY_QUEUE_ADDR_SHIFT) -
        !           637:                    (u_int32_t)ARC_DMA_DVA(sc->sc_requests)));
        !           638:                ccb = &sc->sc_ccbs[letoh32(cmd->cmd.context)];
        !           639:
        !           640:                bus_dmamap_sync(sc->sc_dmat, ARC_DMA_MAP(sc->sc_requests),
        !           641:                    ccb->ccb_offset, ARC_MAX_IOCMDLEN,
        !           642:                    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
        !           643:
        !           644:                arc_scsi_cmd_done(sc, ccb, reg);
        !           645:        }
        !           646:
        !           647:        return (1);
        !           648: }
        !           649:
        !           650: int
        !           651: arc_scsi_cmd(struct scsi_xfer *xs)
        !           652: {
        !           653:        struct scsi_link                *link = xs->sc_link;
        !           654:        struct arc_softc                *sc = link->adapter_softc;
        !           655:        struct arc_ccb                  *ccb;
        !           656:        struct arc_msg_scsicmd          *cmd;
        !           657:        u_int32_t                       reg;
        !           658:        int                             rv = SUCCESSFULLY_QUEUED;
        !           659:        int                             s;
        !           660:
        !           661:        if (xs->cmdlen > ARC_MSG_CDBLEN) {
        !           662:                bzero(&xs->sense, sizeof(xs->sense));
        !           663:                xs->sense.error_code = SSD_ERRCODE_VALID | 0x70;
        !           664:                xs->sense.flags = SKEY_ILLEGAL_REQUEST;
        !           665:                xs->sense.add_sense_code = 0x20;
        !           666:                xs->error = XS_SENSE;
        !           667:                s = splbio();
        !           668:                scsi_done(xs);
        !           669:                splx(s);
        !           670:                return (COMPLETE);
        !           671:        }
        !           672:
        !           673:        s = splbio();
        !           674:        ccb = arc_get_ccb(sc);
        !           675:        splx(s);
        !           676:        if (ccb == NULL) {
        !           677:                xs->error = XS_DRIVER_STUFFUP;
        !           678:                s = splbio();
        !           679:                scsi_done(xs);
        !           680:                splx(s);
        !           681:                return (COMPLETE);
        !           682:        }
        !           683:
        !           684:        ccb->ccb_xs = xs;
        !           685:
        !           686:        if (arc_load_xs(ccb) != 0) {
        !           687:                xs->error = XS_DRIVER_STUFFUP;
        !           688:                s = splbio();
        !           689:                arc_put_ccb(sc, ccb);
        !           690:                scsi_done(xs);
        !           691:                splx(s);
        !           692:                return (COMPLETE);
        !           693:        }
        !           694:
        !           695:        cmd = &ccb->ccb_cmd->cmd;
        !           696:        reg = ccb->ccb_cmd_post;
        !           697:
        !           698:        /* bus is always 0 */
        !           699:        cmd->target = link->target;
        !           700:        cmd->lun = link->lun;
        !           701:        cmd->function = 1; /* XXX magic number */
        !           702:
        !           703:        cmd->cdb_len = xs->cmdlen;
        !           704:        cmd->sgl_len = ccb->ccb_dmamap->dm_nsegs;
        !           705:        if (xs->flags & SCSI_DATA_OUT)
        !           706:                cmd->flags = ARC_MSG_SCSICMD_FLAG_WRITE;
        !           707:        if (ccb->ccb_dmamap->dm_nsegs > ARC_SGL_256LEN) {
        !           708:                cmd->flags |= ARC_MSG_SCSICMD_FLAG_SGL_BSIZE_512;
        !           709:                reg |= ARC_REG_POST_QUEUE_BIGFRAME;
        !           710:        }
        !           711:
        !           712:        cmd->context = htole32(ccb->ccb_id);
        !           713:        cmd->data_len = htole32(xs->datalen);
        !           714:
        !           715:        bcopy(xs->cmd, cmd->cdb, xs->cmdlen);
        !           716:
        !           717:        /* we've built the command, let's put it on the hw */
        !           718:        bus_dmamap_sync(sc->sc_dmat, ARC_DMA_MAP(sc->sc_requests),
        !           719:            ccb->ccb_offset, ARC_MAX_IOCMDLEN,
        !           720:            BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
        !           721:
        !           722:        s = splbio();
        !           723:        arc_push(sc, reg);
        !           724:        if (xs->flags & SCSI_POLL) {
        !           725:                rv = COMPLETE;
        !           726:                if (arc_complete(sc, ccb, xs->timeout) != 0) {
        !           727:                        xs->error = XS_DRIVER_STUFFUP;
        !           728:                        scsi_done(xs);
        !           729:                }
        !           730:        }
        !           731:        splx(s);
        !           732:
        !           733:        return (rv);
        !           734: }
        !           735:
        !           736: int
        !           737: arc_load_xs(struct arc_ccb *ccb)
        !           738: {
        !           739:        struct arc_softc                *sc = ccb->ccb_sc;
        !           740:        struct scsi_xfer                *xs = ccb->ccb_xs;
        !           741:        bus_dmamap_t                    dmap = ccb->ccb_dmamap;
        !           742:        struct arc_sge                  *sgl = ccb->ccb_cmd->sgl, *sge;
        !           743:        u_int64_t                       addr;
        !           744:        int                             i, error;
        !           745:
        !           746:        if (xs->datalen == 0)
        !           747:                return (0);
        !           748:
        !           749:        error = bus_dmamap_load(sc->sc_dmat, dmap,
        !           750:            xs->data, xs->datalen, NULL,
        !           751:            (xs->flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
        !           752:        if (error != 0) {
        !           753:                printf("%s: error %d loading dmamap\n", DEVNAME(sc), error);
        !           754:                return (1);
        !           755:        }
        !           756:
        !           757:        for (i = 0; i < dmap->dm_nsegs; i++) {
        !           758:                sge = &sgl[i];
        !           759:
        !           760:                sge->sg_hdr = htole32(ARC_SGE_64BIT | dmap->dm_segs[i].ds_len);
        !           761:                addr = dmap->dm_segs[i].ds_addr;
        !           762:                sge->sg_hi_addr = htole32((u_int32_t)(addr >> 32));
        !           763:                sge->sg_lo_addr = htole32((u_int32_t)addr);
        !           764:        }
        !           765:
        !           766:        bus_dmamap_sync(sc->sc_dmat, dmap, 0, dmap->dm_mapsize,
        !           767:            (xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_PREREAD :
        !           768:            BUS_DMASYNC_PREWRITE);
        !           769:
        !           770:        return (0);
        !           771: }
        !           772:
        !           773: void
        !           774: arc_scsi_cmd_done(struct arc_softc *sc, struct arc_ccb *ccb, u_int32_t reg)
        !           775: {
        !           776:        struct scsi_xfer                *xs = ccb->ccb_xs;
        !           777:        struct arc_msg_scsicmd          *cmd;
        !           778:
        !           779:        if (xs->datalen != 0) {
        !           780:                bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap, 0,
        !           781:                    ccb->ccb_dmamap->dm_mapsize, (xs->flags & SCSI_DATA_IN) ?
        !           782:                    BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
        !           783:                bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap);
        !           784:        }
        !           785:
        !           786:        /* timeout_del */
        !           787:        xs->flags |= ITSDONE;
        !           788:
        !           789:        if (reg & ARC_REG_REPLY_QUEUE_ERR) {
        !           790:                cmd = &ccb->ccb_cmd->cmd;
        !           791:
        !           792:                switch (cmd->status) {
        !           793:                case ARC_MSG_STATUS_SELTIMEOUT:
        !           794:                case ARC_MSG_STATUS_ABORTED:
        !           795:                case ARC_MSG_STATUS_INIT_FAIL:
        !           796:                        xs->status = SCSI_OK;
        !           797:                        xs->error = XS_SELTIMEOUT;
        !           798:                        break;
        !           799:
        !           800:                case SCSI_CHECK:
        !           801:                        bzero(&xs->sense, sizeof(xs->sense));
        !           802:                        bcopy(cmd->sense_data, &xs->sense,
        !           803:                            min(ARC_MSG_SENSELEN, sizeof(xs->sense)));
        !           804:                        xs->sense.error_code = SSD_ERRCODE_VALID | 0x70;
        !           805:                        xs->status = SCSI_CHECK;
        !           806:                        xs->error = XS_SENSE;
        !           807:                        xs->resid = 0;
        !           808:                        break;
        !           809:
        !           810:                default:
        !           811:                        /* unknown device status */
        !           812:                        xs->error = XS_BUSY; /* try again later? */
        !           813:                        xs->status = SCSI_BUSY;
        !           814:                        break;
        !           815:                }
        !           816:        } else {
        !           817:                xs->status = SCSI_OK;
        !           818:                xs->error = XS_NOERROR;
        !           819:                xs->resid = 0;
        !           820:        }
        !           821:
        !           822:        arc_put_ccb(sc, ccb);
        !           823:        scsi_done(xs);
        !           824: }
        !           825:
        !           826: int
        !           827: arc_complete(struct arc_softc *sc, struct arc_ccb *nccb, int timeout)
        !           828: {
        !           829:        struct arc_ccb                  *ccb = NULL;
        !           830:        char                            *kva = ARC_DMA_KVA(sc->sc_requests);
        !           831:        struct arc_io_cmd               *cmd;
        !           832:        u_int32_t                       reg;
        !           833:
        !           834:        do {
        !           835:                reg = arc_pop(sc);
        !           836:                if (reg == 0xffffffff) {
        !           837:                        if (timeout-- == 0)
        !           838:                                return (1);
        !           839:
        !           840:                        delay(1000);
        !           841:                        continue;
        !           842:                }
        !           843:
        !           844:                cmd = (struct arc_io_cmd *)(kva +
        !           845:                    ((reg << ARC_REG_REPLY_QUEUE_ADDR_SHIFT) -
        !           846:                    ARC_DMA_DVA(sc->sc_requests)));
        !           847:                ccb = &sc->sc_ccbs[letoh32(cmd->cmd.context)];
        !           848:
        !           849:                bus_dmamap_sync(sc->sc_dmat, ARC_DMA_MAP(sc->sc_requests),
        !           850:                    ccb->ccb_offset, ARC_MAX_IOCMDLEN,
        !           851:                    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
        !           852:
        !           853:                arc_scsi_cmd_done(sc, ccb, reg);
        !           854:        } while (nccb != ccb);
        !           855:
        !           856:        return (0);
        !           857: }
        !           858:
        !           859: void
        !           860: arc_minphys(struct buf *bp)
        !           861: {
        !           862:        if (bp->b_bcount > MAXPHYS)
        !           863:                bp->b_bcount = MAXPHYS;
        !           864:        minphys(bp);
        !           865: }
        !           866:
        !           867: int
        !           868: arc_map_pci_resources(struct arc_softc *sc, struct pci_attach_args *pa)
        !           869: {
        !           870:        pcireg_t                        memtype;
        !           871:        pci_intr_handle_t               ih;
        !           872:        const char                      *intrstr;
        !           873:
        !           874:        sc->sc_pc = pa->pa_pc;
        !           875:        sc->sc_tag = pa->pa_tag;
        !           876:        sc->sc_dmat = pa->pa_dmat;
        !           877:
        !           878:        memtype = pci_mapreg_type(sc->sc_pc, sc->sc_tag, ARC_PCI_BAR);
        !           879:        if (pci_mapreg_map(pa, ARC_PCI_BAR, memtype, 0, &sc->sc_iot,
        !           880:            &sc->sc_ioh, NULL, &sc->sc_ios, 0) != 0) {
        !           881:                printf(": unable to map system interface register\n");
        !           882:                return(1);
        !           883:        }
        !           884:
        !           885:        if (pci_intr_map(pa, &ih) != 0) {
        !           886:                printf(": unable to map interrupt\n");
        !           887:                goto unmap;
        !           888:        }
        !           889:        intrstr = pci_intr_string(pa->pa_pc, ih);
        !           890:        sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO,
        !           891:            arc_intr, sc, DEVNAME(sc));
        !           892:        if (sc->sc_ih == NULL) {
        !           893:                printf(": unable to map interrupt%s%s\n",
        !           894:                    intrstr == NULL ? "" : " at ",
        !           895:                    intrstr == NULL ? "" : intrstr);
        !           896:                goto unmap;
        !           897:        }
        !           898:        printf(": %s\n", intrstr);
        !           899:
        !           900:        return (0);
        !           901:
        !           902: unmap:
        !           903:        bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
        !           904:        sc->sc_ios = 0;
        !           905:        return (1);
        !           906: }
        !           907:
        !           908: int
        !           909: arc_query_firmware(struct arc_softc *sc)
        !           910: {
        !           911:        struct arc_msg_firmware_info    fwinfo;
        !           912:        char                            string[81]; /* sizeof(vendor)*2+1 */
        !           913:
        !           914:        if (arc_wait_eq(sc, ARC_REG_OUTB_ADDR1, ARC_REG_OUTB_ADDR1_FIRMWARE_OK,
        !           915:            ARC_REG_OUTB_ADDR1_FIRMWARE_OK) != 0) {
        !           916:                printf("%s: timeout waiting for firmware ok\n", DEVNAME(sc));
        !           917:                return (1);
        !           918:        }
        !           919:
        !           920:        if (arc_msg0(sc, ARC_REG_INB_MSG0_GET_CONFIG) != 0) {
        !           921:                printf("%s: timeout waiting for get config\n", DEVNAME(sc));
        !           922:                return (1);
        !           923:        }
        !           924:
        !           925:        arc_read_region(sc, ARC_REG_MSGBUF, &fwinfo, sizeof(fwinfo));
        !           926:
        !           927:        DNPRINTF(ARC_D_INIT, "%s: signature: 0x%08x\n", DEVNAME(sc),
        !           928:            letoh32(fwinfo.signature));
        !           929:
        !           930:        if (letoh32(fwinfo.signature) != ARC_FWINFO_SIGNATURE_GET_CONFIG) {
        !           931:                printf("%s: invalid firmware info from iop\n", DEVNAME(sc));
        !           932:                return (1);
        !           933:        }
        !           934:
        !           935:        DNPRINTF(ARC_D_INIT, "%s: request_len: %d\n", DEVNAME(sc),
        !           936:            letoh32(fwinfo.request_len));
        !           937:        DNPRINTF(ARC_D_INIT, "%s: queue_len: %d\n", DEVNAME(sc),
        !           938:            letoh32(fwinfo.queue_len));
        !           939:        DNPRINTF(ARC_D_INIT, "%s: sdram_size: %d\n", DEVNAME(sc),
        !           940:            letoh32(fwinfo.sdram_size));
        !           941:        DNPRINTF(ARC_D_INIT, "%s: sata_ports: %d\n", DEVNAME(sc),
        !           942:            letoh32(fwinfo.sata_ports), letoh32(fwinfo.sata_ports));
        !           943:
        !           944: #ifdef ARC_DEBUG
        !           945:        scsi_strvis(string, fwinfo.vendor, sizeof(fwinfo.vendor));
        !           946:        DNPRINTF(ARC_D_INIT, "%s: vendor: \"%s\"\n", DEVNAME(sc), string);
        !           947:        scsi_strvis(string, fwinfo.model, sizeof(fwinfo.model));
        !           948:        DNPRINTF(ARC_D_INIT, "%s: model: \"%s\"\n", DEVNAME(sc), string);
        !           949: #endif /* ARC_DEBUG */
        !           950:
        !           951:        scsi_strvis(string, fwinfo.fw_version, sizeof(fwinfo.fw_version));
        !           952:        DNPRINTF(ARC_D_INIT, "%s: model: \"%s\"\n", DEVNAME(sc), string);
        !           953:
        !           954:        if (letoh32(fwinfo.request_len) != ARC_MAX_IOCMDLEN) {
        !           955:                printf("%s: unexpected request frame size (%d != %d)\n",
        !           956:                    DEVNAME(sc), letoh32(fwinfo.request_len), ARC_MAX_IOCMDLEN);
        !           957:                return (1);
        !           958:        }
        !           959:
        !           960:        sc->sc_req_count = letoh32(fwinfo.queue_len);
        !           961:
        !           962:        if (arc_msg0(sc, ARC_REG_INB_MSG0_START_BGRB) != 0) {
        !           963:                printf("%s: timeout waiting to start bg rebuild\n",
        !           964:                    DEVNAME(sc));
        !           965:                return (1);
        !           966:        }
        !           967:
        !           968:        printf("%s: %d SATA Ports, %dMB SDRAM, FW Version: %s\n",
        !           969:            DEVNAME(sc), letoh32(fwinfo.sata_ports),
        !           970:            letoh32(fwinfo.sdram_size), string);
        !           971:
        !           972:        return (0);
        !           973: }
        !           974:
        !           975: #if NBIO > 0
        !           976: int
        !           977: arc_bioctl(struct device *self, u_long cmd, caddr_t addr)
        !           978: {
        !           979:        struct arc_softc                *sc = (struct arc_softc *)self;
        !           980:        int                             error = 0;
        !           981:
        !           982:        switch (cmd) {
        !           983:        case BIOCINQ:
        !           984:                error = arc_bio_inq(sc, (struct bioc_inq *)addr);
        !           985:                break;
        !           986:
        !           987:        case BIOCVOL:
        !           988:                error = arc_bio_vol(sc, (struct bioc_vol *)addr);
        !           989:                break;
        !           990:
        !           991:        case BIOCDISK:
        !           992:                error = arc_bio_disk(sc, (struct bioc_disk *)addr);
        !           993:                break;
        !           994:
        !           995:        case BIOCALARM:
        !           996:                error = arc_bio_alarm(sc, (struct bioc_alarm *)addr);
        !           997:                break;
        !           998:
        !           999:        default:
        !          1000:                error = ENOTTY;
        !          1001:                break;
        !          1002:        }
        !          1003:
        !          1004:        return (error);
        !          1005: }
        !          1006:
        !          1007: int
        !          1008: arc_bio_alarm(struct arc_softc *sc, struct bioc_alarm *ba)
        !          1009: {
        !          1010:        u_int8_t                        request[2];
        !          1011:        u_int8_t                        reply[1];
        !          1012:        size_t                          len;
        !          1013:        int                             error = 0;
        !          1014:
        !          1015:        switch (ba->ba_opcode) {
        !          1016:        case BIOC_SAENABLE:
        !          1017:        case BIOC_SADISABLE:
        !          1018:                request[0] = ARC_FW_SET_ALARM;
        !          1019:                request[1] = (ba->ba_opcode == BIOC_SAENABLE) ?
        !          1020:                    ARC_FW_SET_ALARM_ENABLE : ARC_FW_SET_ALARM_DISABLE;
        !          1021:                len = sizeof(request);
        !          1022:
        !          1023:                break;
        !          1024:
        !          1025:        case BIOC_SASILENCE:
        !          1026:                request[0] = ARC_FW_MUTE_ALARM;
        !          1027:                len = 1;
        !          1028:
        !          1029:                break;
        !          1030:
        !          1031:        case BIOC_GASTATUS:
        !          1032:                /* system info is too big/ugly to deal with here */
        !          1033:                return (arc_bio_alarm_state(sc, ba));
        !          1034:
        !          1035:        default:
        !          1036:                return (EOPNOTSUPP);
        !          1037:        }
        !          1038:
        !          1039:        arc_lock(sc);
        !          1040:        error = arc_msgbuf(sc, request, len, reply, sizeof(reply));
        !          1041:        arc_unlock(sc);
        !          1042:
        !          1043:        if (error != 0)
        !          1044:                return (error);
        !          1045:
        !          1046:        if (reply[0] != ARC_FW_CMD_OK)
        !          1047:                return (EIO);
        !          1048:
        !          1049:        return (0);
        !          1050: }
        !          1051:
        !          1052: int
        !          1053: arc_bio_alarm_state(struct arc_softc *sc, struct bioc_alarm *ba)
        !          1054: {
        !          1055:        u_int8_t                        request = ARC_FW_SYSINFO;
        !          1056:        struct arc_fw_sysinfo           *sysinfo;
        !          1057:        int                             error = 0;
        !          1058:
        !          1059:        sysinfo = malloc(sizeof(struct arc_fw_sysinfo), M_TEMP, M_WAITOK);
        !          1060:
        !          1061:        request = ARC_FW_SYSINFO;
        !          1062:
        !          1063:        arc_lock(sc);
        !          1064:        error = arc_msgbuf(sc, &request, sizeof(request),
        !          1065:            sysinfo, sizeof(struct arc_fw_sysinfo));
        !          1066:        arc_unlock(sc);
        !          1067:
        !          1068:        if (error != 0)
        !          1069:                goto out;
        !          1070:
        !          1071:        ba->ba_status = sysinfo->alarm;
        !          1072:
        !          1073: out:
        !          1074:        free(sysinfo, M_TEMP);
        !          1075:        return (error);
        !          1076: }
        !          1077:
        !          1078:
        !          1079: int
        !          1080: arc_bio_inq(struct arc_softc *sc, struct bioc_inq *bi)
        !          1081: {
        !          1082:        u_int8_t                        request[2];
        !          1083:        struct arc_fw_sysinfo           *sysinfo;
        !          1084:        struct arc_fw_volinfo           *volinfo;
        !          1085:        int                             maxvols, nvols = 0, i;
        !          1086:        int                             error = 0;
        !          1087:
        !          1088:        sysinfo = malloc(sizeof(struct arc_fw_sysinfo), M_TEMP, M_WAITOK);
        !          1089:        volinfo = malloc(sizeof(struct arc_fw_volinfo), M_TEMP, M_WAITOK);
        !          1090:
        !          1091:        arc_lock(sc);
        !          1092:
        !          1093:        request[0] = ARC_FW_SYSINFO;
        !          1094:        error = arc_msgbuf(sc, request, 1, sysinfo,
        !          1095:            sizeof(struct arc_fw_sysinfo));
        !          1096:        if (error != 0)
        !          1097:                goto out;
        !          1098:
        !          1099:        maxvols = sysinfo->max_volume_set;
        !          1100:
        !          1101:        request[0] = ARC_FW_VOLINFO;
        !          1102:        for (i = 0; i < maxvols; i++) {
        !          1103:                request[1] = i;
        !          1104:                error = arc_msgbuf(sc, request, sizeof(request), volinfo,
        !          1105:                    sizeof(struct arc_fw_volinfo));
        !          1106:                if (error != 0)
        !          1107:                        goto out;
        !          1108:
        !          1109:                /*
        !          1110:                 * I can't find an easy way to see if the volume exists or not
        !          1111:                 * except to say that if it has no capacity then it isn't there.
        !          1112:                 * Ignore passthru volumes, bioc_vol doesn't understand them.
        !          1113:                 */
        !          1114:                if ((volinfo->capacity != 0 || volinfo->capacity2 != 0) &&
        !          1115:                    volinfo->raid_level != ARC_FW_VOL_RAIDLEVEL_PASSTHRU)
        !          1116:                        nvols++;
        !          1117:        }
        !          1118:
        !          1119:        strlcpy(bi->bi_dev, DEVNAME(sc), sizeof(bi->bi_dev));
        !          1120:        bi->bi_novol = nvols;
        !          1121: out:
        !          1122:        arc_unlock(sc);
        !          1123:        free(volinfo, M_TEMP);
        !          1124:        free(sysinfo, M_TEMP);
        !          1125:        return (error);
        !          1126: }
        !          1127:
        !          1128: int
        !          1129: arc_bio_getvol(struct arc_softc *sc, int vol, struct arc_fw_volinfo *volinfo)
        !          1130: {
        !          1131:        u_int8_t                        request[2];
        !          1132:        struct arc_fw_sysinfo           *sysinfo;
        !          1133:        int                             error = 0;
        !          1134:        int                             maxvols, nvols = 0, i;
        !          1135:
        !          1136:        sysinfo = malloc(sizeof(struct arc_fw_sysinfo), M_TEMP, M_WAITOK);
        !          1137:
        !          1138:        request[0] = ARC_FW_SYSINFO;
        !          1139:        error = arc_msgbuf(sc, request, 1, sysinfo,
        !          1140:            sizeof(struct arc_fw_sysinfo));
        !          1141:        if (error != 0)
        !          1142:                goto out;
        !          1143:
        !          1144:        maxvols = sysinfo->max_volume_set;
        !          1145:
        !          1146:        request[0] = ARC_FW_VOLINFO;
        !          1147:        for (i = 0; i < maxvols; i++) {
        !          1148:                request[1] = i;
        !          1149:                error = arc_msgbuf(sc, request, sizeof(request), volinfo,
        !          1150:                    sizeof(struct arc_fw_volinfo));
        !          1151:                if (error != 0)
        !          1152:                        goto out;
        !          1153:
        !          1154:                if ((volinfo->capacity == 0 && volinfo->capacity2 == 0) ||
        !          1155:                    volinfo->raid_level == ARC_FW_VOL_RAIDLEVEL_PASSTHRU)
        !          1156:                        continue;
        !          1157:
        !          1158:                if (nvols == vol)
        !          1159:                        break;
        !          1160:
        !          1161:                nvols++;
        !          1162:        }
        !          1163:
        !          1164:        if (nvols != vol ||
        !          1165:            (volinfo->capacity == 0 && volinfo->capacity2 == 0) ||
        !          1166:            volinfo->raid_level == ARC_FW_VOL_RAIDLEVEL_PASSTHRU) {
        !          1167:                error = ENODEV;
        !          1168:                goto out;
        !          1169:        }
        !          1170:
        !          1171: out:
        !          1172:        free(sysinfo, M_TEMP);
        !          1173:        return (error);
        !          1174: }
        !          1175:
        !          1176: int
        !          1177: arc_bio_vol(struct arc_softc *sc, struct bioc_vol *bv)
        !          1178: {
        !          1179:        struct arc_fw_volinfo           *volinfo;
        !          1180:        struct scsi_link                *sc_link;
        !          1181:        struct device                   *dev;
        !          1182:        u_int64_t                       blocks;
        !          1183:        u_int32_t                       status;
        !          1184:        int                             error = 0;
        !          1185:
        !          1186:        volinfo = malloc(sizeof(struct arc_fw_volinfo), M_TEMP, M_WAITOK);
        !          1187:
        !          1188:        arc_lock(sc);
        !          1189:        error = arc_bio_getvol(sc, bv->bv_volid, volinfo);
        !          1190:        arc_unlock(sc);
        !          1191:
        !          1192:        if (error != 0)
        !          1193:                goto out;
        !          1194:
        !          1195:        bv->bv_percent = -1;
        !          1196:        bv->bv_seconds = 0;
        !          1197:
        !          1198:        status = letoh32(volinfo->volume_status);
        !          1199:        if (status == 0x0) {
        !          1200:                if (letoh32(volinfo->fail_mask) == 0x0)
        !          1201:                        bv->bv_status = BIOC_SVONLINE;
        !          1202:                else
        !          1203:                        bv->bv_status = BIOC_SVDEGRADED;
        !          1204:        } else if (status & ARC_FW_VOL_STATUS_NEED_REGEN)
        !          1205:                bv->bv_status = BIOC_SVDEGRADED;
        !          1206:        else if (status & ARC_FW_VOL_STATUS_FAILED)
        !          1207:                bv->bv_status = BIOC_SVOFFLINE;
        !          1208:        else if (status & ARC_FW_VOL_STATUS_INITTING) {
        !          1209:                bv->bv_status = BIOC_SVBUILDING;
        !          1210:                bv->bv_percent = letoh32(volinfo->progress) / 10;
        !          1211:        } else if (status & ARC_FW_VOL_STATUS_REBUILDING) {
        !          1212:                bv->bv_status = BIOC_SVREBUILD;
        !          1213:                bv->bv_percent = letoh32(volinfo->progress) / 10;
        !          1214:        }
        !          1215:
        !          1216:        blocks = (u_int64_t)letoh32(volinfo->capacity2) << 32;
        !          1217:        blocks += (u_int64_t)letoh32(volinfo->capacity);
        !          1218:        bv->bv_size = blocks * ARC_BLOCKSIZE; /* XXX */
        !          1219:
        !          1220:        switch (volinfo->raid_level) {
        !          1221:        case ARC_FW_VOL_RAIDLEVEL_0:
        !          1222:                bv->bv_level = 0;
        !          1223:                break;
        !          1224:        case ARC_FW_VOL_RAIDLEVEL_1:
        !          1225:                bv->bv_level = 1;
        !          1226:                break;
        !          1227:        case ARC_FW_VOL_RAIDLEVEL_3:
        !          1228:                bv->bv_level = 3;
        !          1229:                break;
        !          1230:        case ARC_FW_VOL_RAIDLEVEL_5:
        !          1231:                bv->bv_level = 5;
        !          1232:                break;
        !          1233:        case ARC_FW_VOL_RAIDLEVEL_6:
        !          1234:                bv->bv_level = 6;
        !          1235:                break;
        !          1236:        case ARC_FW_VOL_RAIDLEVEL_PASSTHRU:
        !          1237:        default:
        !          1238:                bv->bv_level = -1;
        !          1239:                break;
        !          1240:        }
        !          1241:
        !          1242:        bv->bv_nodisk = volinfo->member_disks;
        !          1243:        sc_link = sc->sc_scsibus->sc_link[volinfo->scsi_attr.target]
        !          1244:            [volinfo->scsi_attr.lun];
        !          1245:        if (sc_link != NULL) {
        !          1246:                dev = sc_link->device_softc;
        !          1247:                strlcpy(bv->bv_dev, dev->dv_xname, sizeof(bv->bv_dev));
        !          1248:        }
        !          1249:
        !          1250: out:
        !          1251:        free(volinfo, M_TEMP);
        !          1252:        return (error);
        !          1253: }
        !          1254:
        !          1255: int
        !          1256: arc_bio_disk(struct arc_softc *sc, struct bioc_disk *bd)
        !          1257: {
        !          1258:        u_int8_t                        request[2];
        !          1259:        struct arc_fw_volinfo           *volinfo;
        !          1260:        struct arc_fw_raidinfo          *raidinfo;
        !          1261:        struct arc_fw_diskinfo          *diskinfo;
        !          1262:        int                             error = 0;
        !          1263:        u_int64_t                       blocks;
        !          1264:        char                            model[81];
        !          1265:        char                            serial[41];
        !          1266:        char                            rev[17];
        !          1267:
        !          1268:        volinfo = malloc(sizeof(struct arc_fw_volinfo), M_TEMP, M_WAITOK);
        !          1269:        raidinfo = malloc(sizeof(struct arc_fw_raidinfo), M_TEMP, M_WAITOK);
        !          1270:        diskinfo = malloc(sizeof(struct arc_fw_diskinfo), M_TEMP, M_WAITOK);
        !          1271:
        !          1272:        arc_lock(sc);
        !          1273:
        !          1274:        error = arc_bio_getvol(sc, bd->bd_volid, volinfo);
        !          1275:        if (error != 0)
        !          1276:                goto out;
        !          1277:
        !          1278:        request[0] = ARC_FW_RAIDINFO;
        !          1279:        request[1] = volinfo->raid_set_number;
        !          1280:        error = arc_msgbuf(sc, request, sizeof(request), raidinfo,
        !          1281:            sizeof(struct arc_fw_raidinfo));
        !          1282:        if (error != 0)
        !          1283:                goto out;
        !          1284:
        !          1285:        if (bd->bd_diskid > raidinfo->member_devices) {
        !          1286:                error = ENODEV;
        !          1287:                goto out;
        !          1288:        }
        !          1289:
        !          1290:        if (raidinfo->device_array[bd->bd_diskid] == 0xff) {
        !          1291:                /*
        !          1292:                 * the disk doesn't exist anymore. bio is too dumb to be
        !          1293:                 * able to display that, so put it on another bus
        !          1294:                 */
        !          1295:                bd->bd_channel = 1;
        !          1296:                bd->bd_target = 0;
        !          1297:                bd->bd_lun = 0;
        !          1298:                bd->bd_status = BIOC_SDOFFLINE;
        !          1299:                strlcpy(bd->bd_vendor, "disk missing", sizeof(bd->bd_vendor));
        !          1300:                goto out;
        !          1301:        }
        !          1302:
        !          1303:        request[0] = ARC_FW_DISKINFO;
        !          1304:        request[1] = raidinfo->device_array[bd->bd_diskid];
        !          1305:        error = arc_msgbuf(sc, request, sizeof(request), diskinfo,
        !          1306:            sizeof(struct arc_fw_diskinfo));
        !          1307:        if (error != 0)
        !          1308:                goto out;
        !          1309:
        !          1310: #if 0
        !          1311:        bd->bd_channel = diskinfo->scsi_attr.channel;
        !          1312:        bd->bd_target = diskinfo->scsi_attr.target;
        !          1313:        bd->bd_lun = diskinfo->scsi_attr.lun;
        !          1314: #endif
        !          1315:        /*
        !          1316:         * the firwmare doesnt seem to fill scsi_attr in, so fake it with
        !          1317:         * the diskid.
        !          1318:         */
        !          1319:        bd->bd_channel = 0;
        !          1320:        bd->bd_target = raidinfo->device_array[bd->bd_diskid];
        !          1321:        bd->bd_lun = 0;
        !          1322:
        !          1323:        bd->bd_status = BIOC_SDONLINE;
        !          1324:        blocks = (u_int64_t)letoh32(diskinfo->capacity2) << 32;
        !          1325:        blocks += (u_int64_t)letoh32(diskinfo->capacity);
        !          1326:        bd->bd_size = blocks * ARC_BLOCKSIZE; /* XXX */
        !          1327:
        !          1328:        scsi_strvis(model, diskinfo->model, sizeof(diskinfo->model));
        !          1329:        scsi_strvis(serial, diskinfo->serial, sizeof(diskinfo->serial));
        !          1330:        scsi_strvis(rev, diskinfo->firmware_rev,
        !          1331:            sizeof(diskinfo->firmware_rev));
        !          1332:
        !          1333:        snprintf(bd->bd_vendor, sizeof(bd->bd_vendor), "%s %s",
        !          1334:            model, rev);
        !          1335:        strlcpy(bd->bd_serial, serial, sizeof(bd->bd_serial));
        !          1336:
        !          1337: out:
        !          1338:        arc_unlock(sc);
        !          1339:        free(diskinfo, M_TEMP);
        !          1340:        free(raidinfo, M_TEMP);
        !          1341:        free(volinfo, M_TEMP);
        !          1342:        return (error);
        !          1343: }
        !          1344:
        !          1345: u_int8_t
        !          1346: arc_msg_cksum(void *cmd, u_int16_t len)
        !          1347: {
        !          1348:        u_int8_t                        *buf = cmd;
        !          1349:        u_int8_t                        cksum;
        !          1350:        int                             i;
        !          1351:
        !          1352:        cksum = (u_int8_t)(len >> 8) + (u_int8_t)len;
        !          1353:        for (i = 0; i < len; i++)
        !          1354:                cksum += buf[i];
        !          1355:
        !          1356:        return (cksum);
        !          1357: }
        !          1358:
        !          1359:
        !          1360: int
        !          1361: arc_msgbuf(struct arc_softc *sc, void *wptr, size_t wbuflen, void *rptr,
        !          1362:     size_t rbuflen)
        !          1363: {
        !          1364:        u_int8_t                        rwbuf[ARC_REG_IOC_RWBUF_MAXLEN];
        !          1365:        u_int8_t                        *wbuf, *rbuf;
        !          1366:        int                             wlen, wdone = 0, rlen, rdone = 0;
        !          1367:        struct arc_fw_bufhdr            *bufhdr;
        !          1368:        u_int32_t                       reg, rwlen;
        !          1369:        int                             error = 0;
        !          1370: #ifdef ARC_DEBUG
        !          1371:        int                             i;
        !          1372: #endif
        !          1373:
        !          1374:        DNPRINTF(ARC_D_DB, "%s: arc_msgbuf wbuflen: %d rbuflen: %d\n",
        !          1375:            DEVNAME(sc), wbuflen, rbuflen);
        !          1376:
        !          1377:        if (arc_read(sc, ARC_REG_OUTB_DOORBELL) != 0)
        !          1378:                return (EBUSY);
        !          1379:
        !          1380:        wlen = sizeof(struct arc_fw_bufhdr) + wbuflen + 1; /* 1 for cksum */
        !          1381:        wbuf = malloc(wlen, M_TEMP, M_WAITOK);
        !          1382:
        !          1383:        rlen = sizeof(struct arc_fw_bufhdr) + rbuflen + 1; /* 1 for cksum */
        !          1384:        rbuf = malloc(rlen, M_TEMP, M_WAITOK);
        !          1385:
        !          1386:        DNPRINTF(ARC_D_DB, "%s: arc_msgbuf wlen: %d rlen: %d\n", DEVNAME(sc),
        !          1387:            wlen, rlen);
        !          1388:
        !          1389:        bufhdr = (struct arc_fw_bufhdr *)wbuf;
        !          1390:        bufhdr->hdr = arc_fw_hdr;
        !          1391:        bufhdr->len = htole16(wbuflen);
        !          1392:        bcopy(wptr, wbuf + sizeof(struct arc_fw_bufhdr), wbuflen);
        !          1393:        wbuf[wlen - 1] = arc_msg_cksum(wptr, wbuflen);
        !          1394:
        !          1395:        reg = ARC_REG_OUTB_DOORBELL_READ_OK;
        !          1396:
        !          1397:        do {
        !          1398:                if ((reg & ARC_REG_OUTB_DOORBELL_READ_OK) && wdone < wlen) {
        !          1399:                        bzero(rwbuf, sizeof(rwbuf));
        !          1400:                        rwlen = (wlen - wdone) % sizeof(rwbuf);
        !          1401:                        bcopy(&wbuf[wdone], rwbuf, rwlen);
        !          1402:
        !          1403: #ifdef ARC_DEBUG
        !          1404:                        if (arcdebug & ARC_D_DB) {
        !          1405:                                printf("%s: write %d:", DEVNAME(sc), rwlen);
        !          1406:                                for (i = 0; i < rwlen; i++)
        !          1407:                                        printf(" 0x%02x", rwbuf[i]);
        !          1408:                                printf("\n");
        !          1409:                        }
        !          1410: #endif
        !          1411:
        !          1412:                        /* copy the chunk to the hw */
        !          1413:                        arc_write(sc, ARC_REG_IOC_WBUF_LEN, rwlen);
        !          1414:                        arc_write_region(sc, ARC_REG_IOC_WBUF, rwbuf,
        !          1415:                            sizeof(rwbuf));
        !          1416:
        !          1417:                        /* say we have a buffer for the hw */
        !          1418:                        arc_write(sc, ARC_REG_INB_DOORBELL,
        !          1419:                            ARC_REG_INB_DOORBELL_WRITE_OK);
        !          1420:
        !          1421:                        wdone += rwlen;
        !          1422:                }
        !          1423:
        !          1424:                while ((reg = arc_read(sc, ARC_REG_OUTB_DOORBELL)) == 0)
        !          1425:                        arc_wait(sc);
        !          1426:                arc_write(sc, ARC_REG_OUTB_DOORBELL, reg);
        !          1427:
        !          1428:                DNPRINTF(ARC_D_DB, "%s: reg: 0x%08x\n", DEVNAME(sc), reg);
        !          1429:
        !          1430:                if ((reg & ARC_REG_OUTB_DOORBELL_WRITE_OK) && rdone < rlen) {
        !          1431:                        rwlen = arc_read(sc, ARC_REG_IOC_RBUF_LEN);
        !          1432:                        if (rwlen > sizeof(rwbuf)) {
        !          1433:                                DNPRINTF(ARC_D_DB, "%s:  rwlen too big\n",
        !          1434:                                    DEVNAME(sc));
        !          1435:                                error = EIO;
        !          1436:                                goto out;
        !          1437:                        }
        !          1438:
        !          1439:                        arc_read_region(sc, ARC_REG_IOC_RBUF, rwbuf,
        !          1440:                            sizeof(rwbuf));
        !          1441:
        !          1442:                        arc_write(sc, ARC_REG_INB_DOORBELL,
        !          1443:                            ARC_REG_INB_DOORBELL_READ_OK);
        !          1444:
        !          1445: #ifdef ARC_DEBUG
        !          1446:                        printf("%s:  len: %d+%d=%d/%d\n", DEVNAME(sc),
        !          1447:                            rwlen, rdone, rwlen + rdone, rlen);
        !          1448:                        if (arcdebug & ARC_D_DB) {
        !          1449:                                printf("%s: read:", DEVNAME(sc));
        !          1450:                                for (i = 0; i < rwlen; i++)
        !          1451:                                        printf(" 0x%02x", rwbuf[i]);
        !          1452:                                printf("\n");
        !          1453:                        }
        !          1454: #endif
        !          1455:
        !          1456:                        if ((rdone + rwlen) > rlen) {
        !          1457:                                DNPRINTF(ARC_D_DB, "%s:  rwbuf too big\n",
        !          1458:                                    DEVNAME(sc));
        !          1459:                                error = EIO;
        !          1460:                                goto out;
        !          1461:                        }
        !          1462:
        !          1463:                        bcopy(rwbuf, &rbuf[rdone], rwlen);
        !          1464:                        rdone += rwlen;
        !          1465:                }
        !          1466:        } while (rdone != rlen);
        !          1467:
        !          1468:        bufhdr = (struct arc_fw_bufhdr *)rbuf;
        !          1469:        if (memcmp(&bufhdr->hdr, &arc_fw_hdr, sizeof(bufhdr->hdr)) != 0 ||
        !          1470:            bufhdr->len != htole16(rbuflen)) {
        !          1471:                DNPRINTF(ARC_D_DB, "%s:  rbuf hdr is wrong\n", DEVNAME(sc));
        !          1472:                error = EIO;
        !          1473:                goto out;
        !          1474:        }
        !          1475:
        !          1476:        bcopy(rbuf + sizeof(struct arc_fw_bufhdr), rptr, rbuflen);
        !          1477:
        !          1478:        if (rbuf[rlen - 1] != arc_msg_cksum(rptr, rbuflen)) {
        !          1479:                DNPRINTF(ARC_D_DB, "%s:  invalid cksum\n", DEVNAME(sc));
        !          1480:                error = EIO;
        !          1481:                goto out;
        !          1482:        }
        !          1483:
        !          1484: out:
        !          1485:        free(wbuf, M_TEMP);
        !          1486:        free(rbuf, M_TEMP);
        !          1487:
        !          1488:        return (error);
        !          1489: }
        !          1490:
        !          1491: void
        !          1492: arc_lock(struct arc_softc *sc)
        !          1493: {
        !          1494:        int                             s;
        !          1495:
        !          1496:        rw_enter_write(&sc->sc_lock);
        !          1497:        s = splbio();
        !          1498:        arc_write(sc, ARC_REG_INTRMASK, ~ARC_REG_INTRMASK_POSTQUEUE);
        !          1499:        sc->sc_talking = 1;
        !          1500:        splx(s);
        !          1501: }
        !          1502:
        !          1503: void
        !          1504: arc_unlock(struct arc_softc *sc)
        !          1505: {
        !          1506:        int                             s;
        !          1507:
        !          1508:        s = splbio();
        !          1509:        sc->sc_talking = 0;
        !          1510:        arc_write(sc, ARC_REG_INTRMASK,
        !          1511:            ~(ARC_REG_INTRMASK_POSTQUEUE|ARC_REG_INTRMASK_DOORBELL));
        !          1512:        splx(s);
        !          1513:        rw_exit_write(&sc->sc_lock);
        !          1514: }
        !          1515:
        !          1516: void
        !          1517: arc_wait(struct arc_softc *sc)
        !          1518: {
        !          1519:        int                             s;
        !          1520:
        !          1521:        s = splbio();
        !          1522:        arc_write(sc, ARC_REG_INTRMASK,
        !          1523:            ~(ARC_REG_INTRMASK_POSTQUEUE|ARC_REG_INTRMASK_DOORBELL));
        !          1524:        if (tsleep(sc, PWAIT, "arcdb", hz) == EWOULDBLOCK)
        !          1525:                arc_write(sc, ARC_REG_INTRMASK, ~ARC_REG_INTRMASK_POSTQUEUE);
        !          1526:        splx(s);
        !          1527: }
        !          1528:
        !          1529: #ifndef SMALL_KERNEL
        !          1530: void
        !          1531: arc_create_sensors(void *xsc, void *arg)
        !          1532: {
        !          1533:        struct arc_softc        *sc = xsc;
        !          1534:        struct bioc_inq         bi;
        !          1535:        struct bioc_vol         bv;
        !          1536:        int                     i;
        !          1537:
        !          1538:        /*
        !          1539:         * XXX * this is bollocks. the firmware has garbage coming out of it
        !          1540:         * so we have to wait a bit for it to finish spewing.
        !          1541:         */
        !          1542:        tsleep(sc, PWAIT, "arcspew", 2 * hz);
        !          1543:
        !          1544:        bzero(&bi, sizeof(bi));
        !          1545:        if (arc_bio_inq(sc, &bi) != 0) {
        !          1546:                printf("%s: unable to query firmware for sensor info\n",
        !          1547:                    DEVNAME(sc));
        !          1548:                return;
        !          1549:        }
        !          1550:        sc->sc_nsensors = bi.bi_novol;
        !          1551:
        !          1552:        sc->sc_sensors = malloc(sizeof(struct ksensor) * sc->sc_nsensors,
        !          1553:            M_DEVBUF, M_WAITOK);
        !          1554:        bzero(sc->sc_sensors, sizeof(struct ksensor) * sc->sc_nsensors);
        !          1555:
        !          1556:        strlcpy(sc->sc_sensordev.xname, DEVNAME(sc),
        !          1557:            sizeof(sc->sc_sensordev.xname));
        !          1558:
        !          1559:        for (i = 0; i < sc->sc_nsensors; i++) {
        !          1560:                bzero(&bv, sizeof(bv));
        !          1561:                bv.bv_volid = i;
        !          1562:                if (arc_bio_vol(sc, &bv) != 0)
        !          1563:                        goto bad;
        !          1564:
        !          1565:                sc->sc_sensors[i].type = SENSOR_DRIVE;
        !          1566:                sc->sc_sensors[i].status = SENSOR_S_UNKNOWN;
        !          1567:
        !          1568:                strlcpy(sc->sc_sensors[i].desc, bv.bv_dev,
        !          1569:                    sizeof(sc->sc_sensors[i].desc));
        !          1570:
        !          1571:                sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]);
        !          1572:        }
        !          1573:
        !          1574:        if (sensor_task_register(sc, arc_refresh_sensors, 120) == NULL)
        !          1575:                goto bad;
        !          1576:
        !          1577:        sensordev_install(&sc->sc_sensordev);
        !          1578:
        !          1579:        return;
        !          1580:
        !          1581: bad:
        !          1582:        free(sc->sc_sensors, M_DEVBUF);
        !          1583: }
        !          1584:
        !          1585: void
        !          1586: arc_refresh_sensors(void *arg)
        !          1587: {
        !          1588:        struct arc_softc        *sc = arg;
        !          1589:        struct bioc_vol         bv;
        !          1590:        int                     i;
        !          1591:
        !          1592:        for (i = 0; i < sc->sc_nsensors; i++) {
        !          1593:                bzero(&bv, sizeof(bv));
        !          1594:                bv.bv_volid = i;
        !          1595:                if (arc_bio_vol(sc, &bv)) {
        !          1596:                        sc->sc_sensors[i].flags = SENSOR_FINVALID;
        !          1597:                        return;
        !          1598:                }
        !          1599:
        !          1600:                switch(bv.bv_status) {
        !          1601:                case BIOC_SVOFFLINE:
        !          1602:                        sc->sc_sensors[i].value = SENSOR_DRIVE_FAIL;
        !          1603:                        sc->sc_sensors[i].status = SENSOR_S_CRIT;
        !          1604:                        break;
        !          1605:
        !          1606:                case BIOC_SVDEGRADED:
        !          1607:                        sc->sc_sensors[i].value = SENSOR_DRIVE_PFAIL;
        !          1608:                        sc->sc_sensors[i].status = SENSOR_S_WARN;
        !          1609:                        break;
        !          1610:
        !          1611:                case BIOC_SVSCRUB:
        !          1612:                case BIOC_SVONLINE:
        !          1613:                        sc->sc_sensors[i].value = SENSOR_DRIVE_ONLINE;
        !          1614:                        sc->sc_sensors[i].status = SENSOR_S_OK;
        !          1615:                        break;
        !          1616:
        !          1617:                case BIOC_SVINVALID:
        !          1618:                        /* FALLTRHOUGH */
        !          1619:                default:
        !          1620:                        sc->sc_sensors[i].value = 0; /* unknown */
        !          1621:                        sc->sc_sensors[i].status = SENSOR_S_UNKNOWN;
        !          1622:                }
        !          1623:
        !          1624:        }
        !          1625: }
        !          1626: #endif /* SMALL_KERNEL */
        !          1627: #endif /* NBIO > 0 */
        !          1628:
        !          1629: u_int32_t
        !          1630: arc_read(struct arc_softc *sc, bus_size_t r)
        !          1631: {
        !          1632:        u_int32_t                       v;
        !          1633:
        !          1634:        bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4,
        !          1635:            BUS_SPACE_BARRIER_READ);
        !          1636:        v = bus_space_read_4(sc->sc_iot, sc->sc_ioh, r);
        !          1637:
        !          1638:        DNPRINTF(ARC_D_RW, "%s: arc_read 0x%x 0x%08x\n", DEVNAME(sc), r, v);
        !          1639:
        !          1640:        return (v);
        !          1641: }
        !          1642:
        !          1643: void
        !          1644: arc_read_region(struct arc_softc *sc, bus_size_t r, void *buf, size_t len)
        !          1645: {
        !          1646:        bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, len,
        !          1647:            BUS_SPACE_BARRIER_READ);
        !          1648:        bus_space_read_raw_region_4(sc->sc_iot, sc->sc_ioh, r, buf, len);
        !          1649: }
        !          1650:
        !          1651: void
        !          1652: arc_write(struct arc_softc *sc, bus_size_t r, u_int32_t v)
        !          1653: {
        !          1654:        DNPRINTF(ARC_D_RW, "%s: arc_write 0x%x 0x%08x\n", DEVNAME(sc), r, v);
        !          1655:
        !          1656:        bus_space_write_4(sc->sc_iot, sc->sc_ioh, r, v);
        !          1657:        bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4,
        !          1658:            BUS_SPACE_BARRIER_WRITE);
        !          1659: }
        !          1660:
        !          1661: void
        !          1662: arc_write_region(struct arc_softc *sc, bus_size_t r, void *buf, size_t len)
        !          1663: {
        !          1664:        bus_space_write_raw_region_4(sc->sc_iot, sc->sc_ioh, r, buf, len);
        !          1665:        bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, len,
        !          1666:            BUS_SPACE_BARRIER_WRITE);
        !          1667: }
        !          1668:
        !          1669: int
        !          1670: arc_wait_eq(struct arc_softc *sc, bus_size_t r, u_int32_t mask,
        !          1671:     u_int32_t target)
        !          1672: {
        !          1673:        int                             i;
        !          1674:
        !          1675:        DNPRINTF(ARC_D_RW, "%s: arc_wait_eq 0x%x 0x%08x 0x%08x\n",
        !          1676:            DEVNAME(sc), r, mask, target);
        !          1677:
        !          1678:        for (i = 0; i < 10000; i++) {
        !          1679:                if ((arc_read(sc, r) & mask) == target)
        !          1680:                        return (0);
        !          1681:                delay(1000);
        !          1682:        }
        !          1683:
        !          1684:        return (1);
        !          1685: }
        !          1686:
        !          1687: int
        !          1688: arc_wait_ne(struct arc_softc *sc, bus_size_t r, u_int32_t mask,
        !          1689:     u_int32_t target)
        !          1690: {
        !          1691:        int                             i;
        !          1692:
        !          1693:        DNPRINTF(ARC_D_RW, "%s: arc_wait_ne 0x%x 0x%08x 0x%08x\n",
        !          1694:            DEVNAME(sc), r, mask, target);
        !          1695:
        !          1696:        for (i = 0; i < 10000; i++) {
        !          1697:                if ((arc_read(sc, r) & mask) != target)
        !          1698:                        return (0);
        !          1699:                delay(1000);
        !          1700:        }
        !          1701:
        !          1702:        return (1);
        !          1703: }
        !          1704:
        !          1705: int
        !          1706: arc_msg0(struct arc_softc *sc, u_int32_t m)
        !          1707: {
        !          1708:        /* post message */
        !          1709:        arc_write(sc, ARC_REG_INB_MSG0, m);
        !          1710:        /* wait for the fw to do it */
        !          1711:        if (arc_wait_eq(sc, ARC_REG_INTRSTAT, ARC_REG_INTRSTAT_MSG0,
        !          1712:            ARC_REG_INTRSTAT_MSG0) != 0)
        !          1713:                return (1);
        !          1714:
        !          1715:        /* ack it */
        !          1716:        arc_write(sc, ARC_REG_INTRSTAT, ARC_REG_INTRSTAT_MSG0);
        !          1717:
        !          1718:        return (0);
        !          1719: }
        !          1720:
        !          1721: struct arc_dmamem *
        !          1722: arc_dmamem_alloc(struct arc_softc *sc, size_t size)
        !          1723: {
        !          1724:        struct arc_dmamem               *adm;
        !          1725:        int                             nsegs;
        !          1726:
        !          1727:        adm = malloc(sizeof(struct arc_dmamem), M_DEVBUF, M_NOWAIT);
        !          1728:        if (adm == NULL)
        !          1729:                return (NULL);
        !          1730:
        !          1731:        bzero(adm, sizeof(struct arc_dmamem));
        !          1732:        adm->adm_size = size;
        !          1733:
        !          1734:        if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
        !          1735:            BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &adm->adm_map) != 0)
        !          1736:                goto admfree;
        !          1737:
        !          1738:        if (bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &adm->adm_seg,
        !          1739:            1, &nsegs, BUS_DMA_NOWAIT) != 0)
        !          1740:                goto destroy;
        !          1741:
        !          1742:        if (bus_dmamem_map(sc->sc_dmat, &adm->adm_seg, nsegs, size,
        !          1743:            &adm->adm_kva, BUS_DMA_NOWAIT) != 0)
        !          1744:                goto free;
        !          1745:
        !          1746:        if (bus_dmamap_load(sc->sc_dmat, adm->adm_map, adm->adm_kva, size,
        !          1747:            NULL, BUS_DMA_NOWAIT) != 0)
        !          1748:                goto unmap;
        !          1749:
        !          1750:        bzero(adm->adm_kva, size);
        !          1751:
        !          1752:        return (adm);
        !          1753:
        !          1754: unmap:
        !          1755:        bus_dmamem_unmap(sc->sc_dmat, adm->adm_kva, size);
        !          1756: free:
        !          1757:        bus_dmamem_free(sc->sc_dmat, &adm->adm_seg, 1);
        !          1758: destroy:
        !          1759:        bus_dmamap_destroy(sc->sc_dmat, adm->adm_map);
        !          1760: admfree:
        !          1761:        free(adm, M_DEVBUF);
        !          1762:
        !          1763:        return (NULL);
        !          1764: }
        !          1765:
        !          1766: void
        !          1767: arc_dmamem_free(struct arc_softc *sc, struct arc_dmamem *adm)
        !          1768: {
        !          1769:        bus_dmamap_unload(sc->sc_dmat, adm->adm_map);
        !          1770:        bus_dmamem_unmap(sc->sc_dmat, adm->adm_kva, adm->adm_size);
        !          1771:        bus_dmamem_free(sc->sc_dmat, &adm->adm_seg, 1);
        !          1772:        bus_dmamap_destroy(sc->sc_dmat, adm->adm_map);
        !          1773:        free(adm, M_DEVBUF);
        !          1774: }
        !          1775:
        !          1776: int
        !          1777: arc_alloc_ccbs(struct arc_softc *sc)
        !          1778: {
        !          1779:        struct arc_ccb                  *ccb;
        !          1780:        u_int8_t                        *cmd;
        !          1781:        int                             i;
        !          1782:
        !          1783:        TAILQ_INIT(&sc->sc_ccb_free);
        !          1784:
        !          1785:        sc->sc_ccbs = malloc(sizeof(struct arc_ccb) * sc->sc_req_count,
        !          1786:            M_DEVBUF, M_WAITOK);
        !          1787:        bzero(sc->sc_ccbs, sizeof(struct arc_ccb) * sc->sc_req_count);
        !          1788:
        !          1789:        sc->sc_requests = arc_dmamem_alloc(sc,
        !          1790:            ARC_MAX_IOCMDLEN * sc->sc_req_count);
        !          1791:        if (sc->sc_requests == NULL) {
        !          1792:                printf("%s: unable to allocate ccb dmamem\n", DEVNAME(sc));
        !          1793:                goto free_ccbs;
        !          1794:        }
        !          1795:        cmd = ARC_DMA_KVA(sc->sc_requests);
        !          1796:
        !          1797:        for (i = 0; i < sc->sc_req_count; i++) {
        !          1798:                ccb = &sc->sc_ccbs[i];
        !          1799:
        !          1800:                if (bus_dmamap_create(sc->sc_dmat, MAXPHYS, ARC_SGL_MAXLEN,
        !          1801:                    MAXPHYS, 0, 0, &ccb->ccb_dmamap) != 0) {
        !          1802:                        printf("%s: unable to create dmamap for ccb %d\n",
        !          1803:                            DEVNAME(sc), i);
        !          1804:                        goto free_maps;
        !          1805:                }
        !          1806:
        !          1807:                ccb->ccb_sc = sc;
        !          1808:                ccb->ccb_id = i;
        !          1809:                ccb->ccb_offset = ARC_MAX_IOCMDLEN * i;
        !          1810:
        !          1811:                ccb->ccb_cmd = (struct arc_io_cmd *)&cmd[ccb->ccb_offset];
        !          1812:                ccb->ccb_cmd_post = (ARC_DMA_DVA(sc->sc_requests) +
        !          1813:                    ccb->ccb_offset) >> ARC_REG_POST_QUEUE_ADDR_SHIFT;
        !          1814:
        !          1815:                arc_put_ccb(sc, ccb);
        !          1816:        }
        !          1817:
        !          1818:        return (0);
        !          1819:
        !          1820: free_maps:
        !          1821:        while ((ccb = arc_get_ccb(sc)) != NULL)
        !          1822:            bus_dmamap_destroy(sc->sc_dmat, ccb->ccb_dmamap);
        !          1823:        arc_dmamem_free(sc, sc->sc_requests);
        !          1824:
        !          1825: free_ccbs:
        !          1826:        free(sc->sc_ccbs, M_DEVBUF);
        !          1827:
        !          1828:        return (1);
        !          1829: }
        !          1830:
        !          1831: struct arc_ccb *
        !          1832: arc_get_ccb(struct arc_softc *sc)
        !          1833: {
        !          1834:        struct arc_ccb                  *ccb;
        !          1835:
        !          1836:        ccb = TAILQ_FIRST(&sc->sc_ccb_free);
        !          1837:        if (ccb != NULL)
        !          1838:                TAILQ_REMOVE(&sc->sc_ccb_free, ccb, ccb_link);
        !          1839:
        !          1840:        return (ccb);
        !          1841: }
        !          1842:
        !          1843: void
        !          1844: arc_put_ccb(struct arc_softc *sc, struct arc_ccb *ccb)
        !          1845: {
        !          1846:        ccb->ccb_xs = NULL;
        !          1847:        bzero(ccb->ccb_cmd, ARC_MAX_IOCMDLEN);
        !          1848:        TAILQ_INSERT_TAIL(&sc->sc_ccb_free, ccb, ccb_link);
        !          1849: }

CVSweb