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