diff options
Diffstat (limited to 'sys/dev/pci')
-rw-r--r-- | sys/dev/pci/mpii.c | 944 |
1 files changed, 736 insertions, 208 deletions
diff --git a/sys/dev/pci/mpii.c b/sys/dev/pci/mpii.c index 20ca594b492..b9b9a07cf60 100644 --- a/sys/dev/pci/mpii.c +++ b/sys/dev/pci/mpii.c @@ -1,8 +1,9 @@ -/* $OpenBSD: mpii.c,v 1.6 2010/01/09 23:15:07 krw Exp $ */ +/* $OpenBSD: mpii.c,v 1.7 2010/02/20 19:34:08 marco Exp $ */ /* - * Copyright (c) James Giannoules - * Copyright (c) 2005 David Gwynne <dlg@openbsd.org> - * Copyright (c) 2005 Marco Peereboom <marco@openbsd.org> + * Copyright (c) 2010 Mike Belopuhov <mkb@crypt.org.ru> + * Copyright (c) 2009 James Giannoules + * Copyright (c) 2005 - 2010 David Gwynne <dlg@openbsd.org> + * Copyright (c) 2005 - 2010 Marco Peereboom <marco@openbsd.org> * * * Permission to use, copy, modify, and distribute this software for any @@ -30,6 +31,7 @@ #include <sys/kernel.h> #include <sys/rwlock.h> #include <sys/sensors.h> +#include <sys/tree.h> #include <machine/bus.h> @@ -1019,7 +1021,6 @@ struct mpii_cfg_hdr { #define MPII_CONFIG_REQ_PAGE_TYPE_MANUFACTURING (0x09) #define MPII_CONFIG_REQ_PAGE_TYPE_RAID_PD (0x0a) #define MPII_CONFIG_REQ_PAGE_TYPE_EXTENDED (0x0f) -#define MPII_CONFIG_REQ_PAGE_TYPE_DRIVER_MAPPING (0x17) } __packed; struct mpii_ecfg_hdr { @@ -1030,6 +1031,9 @@ struct mpii_ecfg_hdr { u_int16_t ext_page_length; u_int8_t ext_page_type; +#define MPII_CONFIG_REQ_PAGE_TYPE_SAS_DEVICE (0x12) +#define MPII_CONFIG_REQ_PAGE_TYPE_RAID_CONFIG (0x16) +#define MPII_CONFIG_REQ_PAGE_TYPE_DRIVER_MAPPING (0x17) u_int8_t reserved2; } __packed; @@ -1269,52 +1273,45 @@ struct mpii_cfg_fc_device_pg0 { u_int8_t current_bus; } __packed; +#define MPII_CFG_RAID_VOL_ADDR_HANDLE (1<<28) + struct mpii_cfg_raid_vol_pg0 { struct mpii_cfg_hdr config_header; - u_int8_t volume_id; - u_int8_t volume_bus; - u_int8_t volume_ioc; + u_int16_t volume_handle; + u_int8_t volume_state; +#define MPII_CFG_RAID_VOL_0_STATE_MISSING (0x00) +#define MPII_CFG_RAID_VOL_0_STATE_FAILED (0x01) +#define MPII_CFG_RAID_VOL_0_STATE_INITIALIZING (0x02) +#define MPII_CFG_RAID_VOL_0_STATE_ONLINE (0x03) +#define MPII_CFG_RAID_VOL_0_STATE_DEGRADED (0x04) +#define MPII_CFG_RAID_VOL_0_STATE_OPTIMAL (0x05) u_int8_t volume_type; +#define MPII_CFG_RAID_VOL_0_TYPE_RAID0 (0x00) +#define MPII_CFG_RAID_VOL_0_TYPE_RAID1E (0x01) +#define MPII_CFG_RAID_VOL_0_TYPE_RAID1 (0x02) +#define MPII_CFG_RAID_VOL_0_TYPE_RAID10 (0x05) +#define MPII_CFG_RAID_VOL_0_TYPE_UNKNOWN (0xff) - u_int8_t volume_status; -#define MPII_CFG_RAID_VOL_0_STATUS_ENABLED (1<<0) -#define MPII_CFG_RAID_VOL_0_STATUS_QUIESCED (1<<1) -#define MPII_CFG_RAID_VOL_0_STATUS_RESYNCING (1<<2) -#define MPII_CFG_RAID_VOL_0_STATUS_ACTIVE (1<<3) -#define MPII_CFG_RAID_VOL_0_STATUS_BADBLOCK_FULL (1<<4) - u_int8_t volume_state; -#define MPII_CFG_RAID_VOL_0_STATE_OPTIMAL (0x00) -#define MPII_CFG_RAID_VOL_0_STATE_DEGRADED (0x01) -#define MPII_CFG_RAID_VOL_0_STATE_FAILED (0x02) -#define MPII_CFG_RAID_VOL_0_STATE_MISSING (0x03) - u_int16_t reserved1; + u_int32_t volume_status; u_int16_t volume_settings; -#define MPII_CFG_RAID_VOL_0_SETTINGS_WRITE_CACHE_EN (1<<0) -#define MPII_CFG_RAID_VOL_0_SETTINGS_OFFLINE_SMART_ERR (1<<1) -#define MPII_CFG_RAID_VOL_0_SETTINGS_OFFLINE_SMART (1<<2) -#define MPII_CFG_RAID_VOL_0_SETTINGS_AUTO_SWAP (1<<3) -#define MPII_CFG_RAID_VOL_0_SETTINGS_HI_PRI_RESYNC (1<<4) -#define MPII_CFG_RAID_VOL_0_SETTINGS_PROD_SUFFIX (1<<5) -#define MPII_CFG_RAID_VOL_0_SETTINGS_FAST_SCRUB (1<<6) /* obsolete */ -#define MPII_CFG_RAID_VOL_0_SETTINGS_DEFAULTS (1<<15) u_int8_t hot_spare_pool; - u_int8_t reserved2; + u_int8_t reserved1; - u_int32_t max_lba; - - u_int32_t reserved3; + u_int64_t max_lba; u_int32_t stripe_size; - u_int32_t reserved4; + u_int16_t block_size; + u_int16_t reserved2; - u_int32_t reserved5; + u_int8_t phys_disk_types; + u_int8_t resync_rate; + u_int16_t data_scrub_rate; u_int8_t num_phys_disks; - u_int8_t data_scrub_rate; - u_int8_t resync_rate; + u_int16_t reserved3; u_int8_t inactive_status; #define MPII_CFG_RAID_VOL_0_INACTIVE_UNKNOWN (0x00) #define MPII_CFG_RAID_VOL_0_INACTIVE_STALE_META (0x01) @@ -1327,9 +1324,10 @@ struct mpii_cfg_raid_vol_pg0 { } __packed; struct mpii_cfg_raid_vol_pg0_physdisk { - u_int16_t reserved; + u_int8_t raid_set_num; u_int8_t phys_disk_map; u_int8_t phys_disk_num; + u_int8_t reserved; } __packed; struct mpii_cfg_raid_vol_pg1 { @@ -1351,6 +1349,8 @@ struct mpii_cfg_raid_vol_pg1 { u_int32_t reserved3; } __packed; +#define MPII_CFG_RAID_PHYS_DISK_ADDR_NUMBER (1<<28) + struct mpii_cfg_raid_physdisk_pg0 { struct mpii_cfg_hdr config_header; @@ -1369,45 +1369,50 @@ struct mpii_cfg_raid_physdisk_pg0 { u_int32_t reserved1; - u_int8_t ext_disk_id[8]; - - u_int8_t disk_id[16]; - u_int8_t vendor_id[8]; u_int8_t product_id[16]; u_int8_t product_rev[4]; - u_int8_t info[32]; + u_int8_t serial[32]; + + u_int32_t reserved2; - u_int8_t phys_disk_status; + u_int8_t phys_disk_state; +#define MPII_CFG_RAID_PHYDISK_0_STATE_NOTCONFIGURED (0x00) +#define MPII_CFG_RAID_PHYDISK_0_STATE_NOTCOMPATIBLE (0x01) +#define MPII_CFG_RAID_PHYDISK_0_STATE_OFFLINE (0x02) +#define MPII_CFG_RAID_PHYDISK_0_STATE_ONLINE (0x03) +#define MPII_CFG_RAID_PHYDISK_0_STATE_HOTSPARE (0x04) +#define MPII_CFG_RAID_PHYDISK_0_STATE_DEGRADED (0x05) +#define MPII_CFG_RAID_PHYDISK_0_STATE_REBUILDING (0x06) +#define MPII_CFG_RAID_PHYDISK_0_STATE_OPTIMAL (0x07) + u_int8_t offline_reason; +#define MPII_CFG_RAID_PHYDISK_0_OFFLINE_MISSING (0x01) +#define MPII_CFG_RAID_PHYDISK_0_OFFLINE_FAILED (0x01) +#define MPII_CFG_RAID_PHYDISK_0_OFFLINE_INITIALIZING (0x01) +#define MPII_CFG_RAID_PHYDISK_0_OFFLINE_REQUESTED (0x01) +#define MPII_CFG_RAID_PHYDISK_0_OFFLINE_FAILEDREQ (0x01) +#define MPII_CFG_RAID_PHYDISK_0_OFFLINE_OTHER (0xff) + + u_int8_t incompat_reason; + u_int8_t phys_disk_attrs; + + u_int32_t phys_disk_status; #define MPII_CFG_RAID_PHYDISK_0_STATUS_OUTOFSYNC (1<<0) #define MPII_CFG_RAID_PHYDISK_0_STATUS_QUIESCED (1<<1) - u_int8_t phys_disk_state; -#define MPII_CFG_RAID_PHYDISK_0_STATE_ONLINE (0x00) -#define MPII_CFG_RAID_PHYDISK_0_STATE_MISSING (0x01) -#define MPII_CFG_RAID_PHYDISK_0_STATE_INCOMPAT (0x02) -#define MPII_CFG_RAID_PHYDISK_0_STATE_FAILED (0x03) -#define MPII_CFG_RAID_PHYDISK_0_STATE_INIT (0x04) -#define MPII_CFG_RAID_PHYDISK_0_STATE_OFFLINE (0x05) -#define MPII_CFG_RAID_PHYDISK_0_STATE_HOSTFAIL (0x06) -#define MPII_CFG_RAID_PHYDISK_0_STATE_OTHER (0xff) - u_int16_t reserved2; - u_int32_t max_lba; + u_int64_t dev_max_lba; - u_int8_t error_cdb_byte; - u_int8_t error_sense_key; - u_int16_t reserved3; + u_int64_t host_max_lba; + + u_int64_t coerced_max_lba; - u_int16_t error_count; - u_int8_t error_asc; - u_int8_t error_ascq; + u_int16_t block_size; + u_int16_t reserved3; - u_int16_t smart_count; - u_int8_t smart_asc; - u_int8_t smart_ascq; + u_int32_t reserved4; } __packed; struct mpii_cfg_raid_physdisk_pg1 { @@ -1489,7 +1494,16 @@ struct mpii_cfg_sas_dev_pg0 { #define MPII_CFG_SAS_DEV_0_FLAGS_UNSUPPORTED (1<<8) #define MPII_CFG_SAS_DEV_0_FLAGS_SATA_SETTINGS (1<<9) u_int8_t physical_port; - u_int8_t reserved; + u_int8_t max_port_conn; + + u_int64_t device_name; + + u_int8_t port_groups; + u_int8_t dma_group; + u_int8_t ctrl_group; + u_int8_t reserved1; + + u_int64_t reserved2; } __packed; struct mpii_cfg_bios_pg2 { @@ -1518,6 +1532,8 @@ struct mpii_cfg_bios_pg2 { u_int32_t c; } __packed; +#define MPII_CFG_RAID_CONFIG_ACTIVE_CONFIG (2<<28) + struct mpii_cfg_raid_config_pg0 { struct mpii_ecfg_hdr config_header; @@ -1871,6 +1887,7 @@ struct mpii_softc { u_int16_t sc_vd_id_low; u_int16_t sc_vd_id_hi; u_int16_t sc_pd_id_start; + u_int16_t sc_pd_count; u_int16_t sc_vd_count; u_int8_t sc_num_channels; /* XXX not sure these below will stay */ @@ -1949,7 +1966,8 @@ static const struct pci_matchid mpii_devices[] = { int mpii_pci_match(struct device *parent, void *match, void *aux) { - return (pci_matchbyid(aux, mpii_devices, nitems(mpii_devices))); + return (pci_matchbyid(aux, mpii_devices, + sizeof(mpii_devices) / sizeof(mpii_devices[0]))); } void @@ -2076,7 +2094,7 @@ struct scsi_adapter mpii_switch = { mpii_minphys, mpii_scsi_probe, /* XXX JPG scsi_probe may prove useful for mapping nonsense */ NULL, - NULL + mpii_scsi_ioctl }; struct scsi_device mpii_dev = { @@ -2101,7 +2119,8 @@ void mpii_push_replies(struct mpii_softc *); void mpii_start(struct mpii_softc *, struct mpii_ccb *); int mpii_complete(struct mpii_softc *, struct mpii_ccb *, int); int mpii_poll(struct mpii_softc *, struct mpii_ccb *, int); -int mpii_reply(struct mpii_softc *); +int mpii_reply(struct mpii_softc *, + struct mpii_reply_descriptor *); void mpii_init_queues(struct mpii_softc *); @@ -2169,13 +2188,16 @@ void mpii_reorder_vds(struct mpii_softc *); void mpii_reorder_boot_device(struct mpii_softc *); #if NBIO > 0 -int mpii_bio_get_pg0_raid(struct mpii_softc *, int); int mpii_ioctl(struct device *, u_long, caddr_t); int mpii_ioctl_inq(struct mpii_softc *, struct bioc_inq *); int mpii_ioctl_vol(struct mpii_softc *, struct bioc_vol *); int mpii_ioctl_disk(struct mpii_softc *, struct bioc_disk *); -int mpii_ioctl_setstate(struct mpii_softc *, struct bioc_setstate *); +int mpii_bio_hs(struct mpii_softc *, struct bioc_disk *, int, + u_int8_t, int *); +int mpii_bio_disk(struct mpii_softc *, struct bioc_disk *, + u_int8_t); #ifndef SMALL_KERNEL + int mpii_bio_volstate(struct mpii_softc *, struct bioc_vol *); int mpii_create_sensors(struct mpii_softc *); void mpii_refresh_sensors(void *); #endif /* SMALL_KERNEL */ @@ -2193,11 +2215,11 @@ void mpii_refresh_sensors(void *); #define mpii_reply_waiting(s) ((mpii_read_intr((s)) & MPII_INTR_STATUS_REPLY)\ == MPII_INTR_STATUS_REPLY) -#define mpii_read_reply_free(s, v) mpii_read((s), \ +#define mpii_read_reply_free(s) mpii_read((s), \ MPII_REPLY_FREE_HOST_INDEX) #define mpii_write_reply_free(s, v) mpii_write((s), \ MPII_REPLY_FREE_HOST_INDEX, (v)) -#define mpii_read_reply_post(s, v) mpii_read((s), \ +#define mpii_read_reply_post(s) mpii_read((s), \ MPII_REPLY_POST_HOST_INDEX) #define mpii_write_reply_post(s, v) mpii_write((s), \ MPII_REPLY_POST_HOST_INDEX, (v)) @@ -2289,11 +2311,13 @@ mpii_attach(struct mpii_softc *sc) goto free_queues; } +#if 0 if (mpii_get_dpm(sc) != 0) { printf("%s: unable to get driver persistent mapping\n", DEVNAME(sc)); goto free_queues; } +#endif if (mpii_cfg_coalescing(sc) != 0) { printf("%s: unable to configure coalescing\n", DEVNAME(sc)); @@ -2314,19 +2338,17 @@ mpii_attach(struct mpii_softc *sc) DEVNAME(sc)); goto free_dpm; } - - /* enable interrupts */ - mpii_write(sc, MPII_INTR_MASK, MPII_INTR_MASK_DOORBELL - | MPII_INTR_MASK_RESET); - + if (mpii_portenable(sc) != 0) { printf("%s: unable to enable port\n", DEVNAME(sc)); goto free_dev; } /* assume all discovery events are complete by now */ +#if 0 if (sc->sc_discovery_in_progress) printf("%s: warning: discovery still in progress\n", DEVNAME(sc)); +#endif if (mpii_get_bios_pg2(sc) != 0) { printf("%s: unable to get bios page 2\n", DEVNAME(sc)); @@ -2362,6 +2384,22 @@ mpii_attach(struct mpii_softc *sc) sc->sc_scsibus = (struct scsibus_softc *) config_found(&sc->sc_dev, &saa, scsiprint); + /* enable interrupts */ + mpii_write(sc, MPII_INTR_MASK, MPII_INTR_MASK_DOORBELL + | MPII_INTR_MASK_RESET); + +#if NBIO > 0 + if (bio_register(&sc->sc_dev, mpii_ioctl) != 0) + panic("%s: controller registration failed", DEVNAME(sc)); + else + sc->sc_ioctl = mpii_ioctl; + +#ifndef SMALL_KERNEL + if (mpii_create_sensors(sc) != 0) + printf("%s: unable to create sensors\n", DEVNAME(sc)); +#endif +#endif + return (0); free_bios_pg2: @@ -2408,23 +2446,49 @@ mpii_detach(struct mpii_softc *sc) int mpii_intr(void *arg) { - struct mpii_softc *sc = arg; + struct mpii_softc *sc = arg; + struct mpii_reply_descriptor *rdp; + u_int8_t reply_flags; + int rv = 0; - if (mpii_reply(sc) < 0) - return (0); + do { + bus_dmamap_sync(sc->sc_dmat, MPII_DMA_MAP(sc->sc_reply_postq), + 0, 8 * sc->sc_reply_post_qdepth, BUS_DMASYNC_POSTWRITE); - while (mpii_reply(sc) >= 0) - ; - - mpii_write_reply_post(sc, sc->sc_reply_post_host_index); + rdp = &sc->sc_reply_postq_kva[sc->sc_reply_post_host_index]; + reply_flags = (u_int8_t)(rdp->reply_flags) & + MPII_REPLY_DESCR_FLAGS_TYPE_MASK; + if ((reply_flags == MPII_REPLY_DESCR_FLAGS_UNUSED)) + break; + if (rdp->type_dependent2 == 0xffffffff) { + /* + * ioc is still writing to the reply post queue + * race condition - bail! + */ + printf("%s: ioc is writing a reply\n", DEVNAME(sc)); + break; + } + mpii_reply(sc, rdp); + sc->sc_reply_post_host_index = + (sc->sc_reply_post_host_index + 1) % + sc->sc_reply_post_qdepth; + rv |= 1; + } while (1); + + if (rv) + mpii_write_reply_post(sc, sc->sc_reply_post_host_index); - return (1); + return (rv); } void mpii_timeout_xs(void *arg) { -/* XXX */ + struct mpii_ccb *ccb = arg; + struct mpii_softc *sc = ccb->ccb_sc; + + printf("%s: xfer timeout, ccb %d state %d\n", DEVNAME(sc), + ccb->ccb_smid, ccb->ccb_state); } int @@ -2540,7 +2604,6 @@ mpii_load_xs(struct mpii_ccb *ccb) void mpii_minphys(struct buf *bp, struct scsi_link *sl) { - /* XXX */ minphys(bp); } @@ -3063,7 +3126,7 @@ mpii_iocinit(struct mpii_softc *sc) hi_addr = (u_int32_t) ((u_int64_t)MPII_DMA_DVA(sc->sc_replies) >> 32); - iiq.system_reply_address_high = hi_addr; + iiq.system_reply_address_high = htole32(hi_addr); iiq.system_request_frame_base_address = (u_int64_t)MPII_DMA_DVA(sc->sc_requests); @@ -3381,8 +3444,10 @@ mpii_eventnotify(struct mpii_softc *sc) enq->event_masks[1] = htole32(0xfffffffc); enq->event_masks[2] = htole32(0xffffffff); enq->event_masks[3] = htole32(0xffffffff); - + + s = splbio(); mpii_start(sc, ccb); + splx(s); return (0); } @@ -3418,9 +3483,6 @@ mpii_event_process_ir_cfg_change_list(struct mpii_softc *sc, ce = (struct mpii_evt_ir_cfg_element *)(ccl + 1); for (i = 0; i < ccl->num_elements; i++, ce++) { - - for (volid = 0; volid < sc->sc_max_devices; volid++) - type = (letoh16(ce->element_flags) & MPII_EVT_IR_CFG_ELEMENT_EF_ELEMENT_TYPE_MASK); @@ -3440,7 +3502,7 @@ mpii_event_process_ir_cfg_change_list(struct mpii_softc *sc, if (sc->sc_mpii_dev[volid] == NULL) { device = malloc(sizeof(struct mpii_device), - M_DEVBUF, M_ZERO); + M_DEVBUF, M_NOWAIT | M_ZERO); if (device == NULL) { printf("%s: mpii_event_ir_cfg_change_list " "unable to allocate mpii_device\n", @@ -3566,7 +3628,7 @@ mpii_event_process_sas_topo_change(struct mpii_softc *sc, } device = malloc(sizeof(struct mpii_device), - M_DEVBUF, M_ZERO); + M_DEVBUF, M_NOWAIT | M_ZERO); if (device == NULL) { printf("%s: mpii_event_ir_cfg_change_list " "unable to allocate mpii_device\n", @@ -3574,6 +3636,7 @@ mpii_event_process_sas_topo_change(struct mpii_softc *sc, break; } + sc->sc_pd_count++; device->dev_handle = letoh16(pe->attached_dev_handle); device->phy_num = tcl->start_phy_num + i; device->type = MPII_DEV_TYPE_PD; @@ -3748,7 +3811,7 @@ mpii_get_bios_pg2(struct mpii_softc *sc) } pagelen = hdr.page_length * 4; - sc->sc_bios_pg2 = malloc(pagelen, M_TEMP, M_WAITOK|M_CANFAIL); + sc->sc_bios_pg2 = malloc(pagelen, M_TEMP, M_NOWAIT | M_CANFAIL); if (sc->sc_bios_pg2 == NULL) { DNPRINTF(MPII_D_RAID, "%s: mpii_get_bios_pg2 unable to " "allocate space for BIOS page 2\n", DEVNAME(sc)); @@ -3902,7 +3965,7 @@ mpii_get_dpm_pg0(struct mpii_softc *sc, struct mpii_cfg_dpm_pg0 *dpm_page) pagelen = sizeof(struct mpii_ecfg_hdr) + sc->sc_max_dpm_entries * sizeof(struct mpii_dpm_entry); - dpm_page = malloc(pagelen, M_TEMP, M_WAITOK|M_CANFAIL); + dpm_page = malloc(pagelen, M_TEMP, M_NOWAIT | M_CANFAIL); if (dpm_page == NULL) { DNPRINTF(MPII_D_MISC, "%s: mpii_get_dpm_pg0 unable to allocate " "space for device persistence mapping page 0\n", DEVNAME(sc)); @@ -4054,7 +4117,7 @@ mpii_get_ioc_pg8(struct mpii_softc *sc) pagelen = hdr.page_length * 4; /* dwords to bytes */ - page = malloc(pagelen, M_TEMP, M_WAITOK|M_CANFAIL); + page = malloc(pagelen, M_TEMP, M_NOWAIT | M_CANFAIL); if (page == NULL) { DNPRINTF(MPII_D_CFG, "%s: mpii_get_ioc_pg8 unable to allocate " "space for ioc config page 8\n", DEVNAME(sc)); @@ -4079,10 +4142,12 @@ mpii_get_ioc_pg8(struct mpii_softc *sc) DNPRINTF(MPII_D_CFG, "%s: irvolumemappingflags: 0x%04x\n", DEVNAME(sc), letoh16(page->ir_volume_mapping_flags)); +#if 0 if (!(page->flags & MPII_IOC_PG8_FLAGS_ENCLOSURE_SLOT_MAPPING)) /* XXX we don't currently handle persistent mapping mode */ printf("%s: warning: controller requested device persistence " "mapping mode is not supported.\n"); +#endif sc->sc_max_dpm_entries = page->max_persistent_entries; sc->sc_dpm_enabled = (sc->sc_max_dpm_entries) ? 1 : 0; @@ -4183,8 +4248,12 @@ mpii_req_cfg_header(struct mpii_softc *sc, u_int8_t type, u_int8_t number, splx(s); } - if (ccb->ccb_rcb == NULL) - panic("%s: unable to fetch config header\n", DEVNAME(sc)); + if (ccb->ccb_rcb == NULL) { + s = splbio(); + mpii_put_ccb(sc, ccb); + splx(s); + return (1); + } cp = ccb->ccb_rcb->rcb_reply; DNPRINTF(MPII_D_MISC, "%s: action: 0x%02x sgl_flags: 0x%02x " @@ -4219,8 +4288,10 @@ mpii_req_cfg_header(struct mpii_softc *sc, u_int8_t type, u_int8_t number, } else *hdr = cp->config_header; + s = splbio(); mpii_push_reply(sc, ccb->ccb_rcb->rcb_reply_dva); mpii_put_ccb(sc, ccb); + splx(s); return (rv); } @@ -4277,7 +4348,7 @@ mpii_req_cfg_page(struct mpii_softc *sc, u_int32_t address, int flags, cq->page_address = htole32(address); cq->page_buffer.sg_hdr = htole32(MPII_SGE_FL_TYPE_SIMPLE | MPII_SGE_FL_LAST | MPII_SGE_FL_EOB | MPII_SGE_FL_EOL | - (page_length * 4) | + MPII_SGE_FL_SIZE_64 | (page_length * 4) | (read ? MPII_SGE_FL_DIR_IN : MPII_SGE_FL_DIR_OUT)); /* bounce the page via the request space to avoid more bus_dma games */ @@ -4309,7 +4380,9 @@ mpii_req_cfg_page(struct mpii_softc *sc, u_int32_t address, int flags, } if (ccb->ccb_rcb == NULL) { + s = splbio(); mpii_put_ccb(sc, ccb); + splx(s); return (1); } cp = ccb->ccb_rcb->rcb_reply; @@ -4339,99 +4412,64 @@ mpii_req_cfg_page(struct mpii_softc *sc, u_int32_t address, int flags, else if (read) bcopy(kva, page, len); + s = splbio(); mpii_push_reply(sc, ccb->ccb_rcb->rcb_reply_dva); mpii_put_ccb(sc, ccb); + splx(s); return (rv); } int -mpii_reply(struct mpii_softc *sc) +mpii_reply(struct mpii_softc *sc, struct mpii_reply_descriptor *rdp) { - struct mpii_reply_descriptor *rdp; struct mpii_ccb *ccb = NULL; struct mpii_rcb *rcb = NULL; - struct mpii_msg_reply *reply = NULL; u_int8_t reply_flags; - u_int32_t reply_dva, i; + u_int32_t i; int smid; DNPRINTF(MPII_D_INTR, "%s: mpii_reply\n", DEVNAME(sc)); - /* XXX need to change to to be just the reply we expect to read */ - bus_dmamap_sync(sc->sc_dmat, MPII_DMA_MAP(sc->sc_reply_postq), 0, - 8 * sc->sc_reply_post_qdepth, BUS_DMASYNC_POSTWRITE); - - rdp = &sc->sc_reply_postq_kva[sc->sc_reply_post_host_index]; - - reply_flags = (u_int8_t)(rdp->reply_flags) & - MPII_REPLY_DESCR_FLAGS_TYPE_MASK; - - if ((reply_flags == MPII_REPLY_DESCR_FLAGS_UNUSED)) - return (-1); - - if (dwordn(rdp, 1) == 0xffffffff) - /* - * ioc is still writing to the reply post queue - * race condition - bail! - */ - return (-1); - DNPRINTF(MPII_D_INTR, "%s: dword[0]: 0x%08x\n", DEVNAME(sc), letoh32(dwordn(rdp, 0))); DNPRINTF(MPII_D_INTR, "%s: dword[1]: 0x%08x\n", DEVNAME(sc), letoh32(dwordn(rdp, 1))); - switch (reply_flags) { - case MPII_REPLY_DESCR_FLAGS_ADDRESS_REPLY: + reply_flags = (u_int8_t)(rdp->reply_flags) & + MPII_REPLY_DESCR_FLAGS_TYPE_MASK; + + /* smid */ + smid = letoh16(rdp->type_dependent1); + + if (reply_flags == MPII_REPLY_DESCR_FLAGS_ADDRESS_REPLY) { /* reply frame address */ - reply_dva = letoh32(rdp->type_dependent2); - i = (reply_dva - (u_int32_t)MPII_DMA_DVA(sc->sc_replies)) / - MPII_REPLY_SIZE; - + i = (letoh32(rdp->type_dependent2) - + (u_int32_t)MPII_DMA_DVA(sc->sc_replies)) / MPII_REPLY_SIZE; + bus_dmamap_sync(sc->sc_dmat, MPII_DMA_MAP(sc->sc_replies), MPII_REPLY_SIZE * i, MPII_REPLY_SIZE, BUS_DMASYNC_POSTREAD); rcb = &sc->sc_rcbs[i]; - reply = rcb->rcb_reply; - /* fall through */ - default: - /* smid */ - smid = letoh16(rdp->type_dependent1); } DNPRINTF(MPII_D_INTR, "%s: mpii_reply reply_flags: %d smid: %d reply: %p\n", - DEVNAME(sc), reply_flags, smid, reply); + DEVNAME(sc), reply_flags, smid, rcb->rcb_reply); - if (smid) { - ccb = &sc->sc_ccbs[smid - 1]; - - /* XXX why is this necessary ? */ - bus_dmamap_sync(sc->sc_dmat, MPII_DMA_MAP(sc->sc_requests), - ccb->ccb_offset, MPII_REQUEST_SIZE, - BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); - - ccb->ccb_state = MPII_CCB_READY; - ccb->ccb_rcb = rcb; - } - - DNPRINTF(MPII_D_INTR, " rcb: 0x%04x\n", rcb); - - dwordn(rdp, 0) = 0xffffffff; - dwordn(rdp, 1) = 0xffffffff; + memset(rdp, 0xff, sizeof(*rdp)); bus_dmamap_sync(sc->sc_dmat, MPII_DMA_MAP(sc->sc_reply_postq), 8 * sc->sc_reply_post_host_index, 8, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); - - sc->sc_reply_post_host_index = (sc->sc_reply_post_host_index + 1) % - sc->sc_reply_post_qdepth; - if (smid) + if (smid) { + ccb = &sc->sc_ccbs[smid - 1]; + ccb->ccb_state = MPII_CCB_READY; + ccb->ccb_rcb = rcb; ccb->ccb_done(ccb); - else + } else mpii_event_process(sc, rcb->rcb_reply); return (smid); @@ -4465,11 +4503,11 @@ mpii_dmamem_alloc(struct mpii_softc *sc, size_t size) NULL, BUS_DMA_NOWAIT) != 0) goto unmap; - bzero(mdm->mdm_kva, size); + DNPRINTF(MPII_D_MEM, " kva: %p dva: %p map: %p size: %d\n", + mdm->mdm_kva, mdm->mdm_map->dm_segs[0].ds_addr, mdm->mdm_map, + size); - DNPRINTF(MPII_D_MEM, "%s: mpii_dmamem_alloc size: %d mdm: %#x " - "map: %#x nsegs: %d segs: %#x kva: %x\n", - DEVNAME(sc), size, mdm->mdm_map, nsegs, mdm->mdm_seg, mdm->mdm_kva); + bzero(mdm->mdm_kva, size); return (mdm); @@ -4506,7 +4544,7 @@ mpii_alloc_dev(struct mpii_softc *sc) sc->sc_mpii_dev = malloc(sc->sc_max_devices * sizeof(struct mpii_device *), M_DEVBUF, - M_WAITOK | M_CANFAIL | M_ZERO); + M_NOWAIT | M_CANFAIL | M_ZERO); if (sc->sc_mpii_dev == NULL) return (1); @@ -4524,7 +4562,7 @@ mpii_alloc_ccbs(struct mpii_softc *sc) TAILQ_INIT(&sc->sc_ccb_free); sc->sc_ccbs = malloc(sizeof(struct mpii_ccb) * (sc->sc_request_depth-1), - M_DEVBUF, M_WAITOK | M_CANFAIL | M_ZERO); + M_DEVBUF, M_NOWAIT | M_CANFAIL | M_ZERO); if (sc->sc_ccbs == NULL) { printf("%s: unable to allocate ccbs\n", DEVNAME(sc)); return (1); @@ -4593,6 +4631,7 @@ mpii_put_ccb(struct mpii_softc *sc, struct mpii_ccb *ccb) ccb->ccb_state = MPII_CCB_FREE; ccb->ccb_xs = NULL; ccb->ccb_done = NULL; + ccb->ccb_rcb = NULL; bzero(ccb->ccb_cmd, MPII_REQUEST_SIZE); TAILQ_INSERT_TAIL(&sc->sc_ccb_free, ccb, ccb_link); } @@ -4623,7 +4662,7 @@ mpii_alloc_replies(struct mpii_softc *sc) DNPRINTF(MPII_D_MISC, "%s: mpii_alloc_replies\n", DEVNAME(sc)); sc->sc_rcbs = malloc(sc->sc_num_reply_frames * sizeof(struct mpii_rcb), - M_DEVBUF, M_WAITOK|M_CANFAIL); + M_DEVBUF, M_NOWAIT | M_CANFAIL); if (sc->sc_rcbs == NULL) return (1); @@ -4656,11 +4695,13 @@ mpii_push_replies(struct mpii_softc *sc) mpii_push_reply(sc, rcb->rcb_reply_dva); } } + void mpii_start(struct mpii_softc *sc, struct mpii_ccb *ccb) { struct mpii_request_header *rhp; struct mpii_request_descriptor descriptor; + u_int32_t *rdp = (uint32_t *)&descriptor; DNPRINTF(MPII_D_RW, "%s: mpii_start %#x\n", DEVNAME(sc), ccb->ccb_cmd_dva); @@ -4696,24 +4737,22 @@ mpii_start(struct mpii_softc *sc, struct mpii_ccb *ccb) ccb->ccb_state = MPII_CCB_QUEUED; DNPRINTF(MPII_D_RW, "%s: MPII_REQ_DESC_POST_LOW (0x%08x) write " - "0x%08x\n", DEVNAME(sc), MPII_REQ_DESC_POST_LOW, - dwordn(&descriptor, 0)); + "0x%08x\n", DEVNAME(sc), MPII_REQ_DESC_POST_LOW, *rdp); DNPRINTF(MPII_D_RW, "%s: MPII_REQ_DESC_POST_HIGH (0x%08x) write " - "0x%08x\n", DEVNAME(sc), MPII_REQ_DESC_POST_HIGH, - dwordn(&descriptor, 1)); + "0x%08x\n", DEVNAME(sc), MPII_REQ_DESC_POST_HIGH, *(rdp+1)); - /* XXX make this 64 bit? */ - mpii_write(sc, MPII_REQ_DESC_POST_LOW, htole32(dwordn(&descriptor, 0))); - mpii_write(sc, MPII_REQ_DESC_POST_HIGH, - htole32(dwordn(&descriptor, 1))); + mpii_write(sc, MPII_REQ_DESC_POST_LOW, htole32(*rdp)); + mpii_write(sc, MPII_REQ_DESC_POST_HIGH, htole32(*(rdp+1))); } int mpii_complete(struct mpii_softc *sc, struct mpii_ccb *ccb, int timeout) { - int smid = -1; - + struct mpii_reply_descriptor *rdp; + u_int8_t reply_flags; + int smid = -1; + DNPRINTF(MPII_D_INTR, "%s: mpii_complete timeout %d\n", DEVNAME(sc), timeout); @@ -4726,19 +4765,35 @@ mpii_complete(struct mpii_softc *sc, struct mpii_ccb *ccb, int timeout) delay(1000); continue; } - - smid = mpii_reply(sc); - - /* generates PCI write every completed reply, but - * prevents deadlock waiting for specific smid - */ - mpii_write_reply_post(sc, sc->sc_reply_post_host_index); - - DNPRINTF(MPII_D_INTR, "%s: mpii_complete call to mpii_reply returned: %d\n", - DEVNAME(sc), smid); + bus_dmamap_sync(sc->sc_dmat, MPII_DMA_MAP(sc->sc_reply_postq), + 0, 8 * sc->sc_reply_post_qdepth, BUS_DMASYNC_POSTWRITE); + + rdp = &sc->sc_reply_postq_kva[sc->sc_reply_post_host_index]; + reply_flags = (u_int8_t)(rdp->reply_flags) & + MPII_REPLY_DESCR_FLAGS_TYPE_MASK; + if ((reply_flags == MPII_REPLY_DESCR_FLAGS_UNUSED)) + continue; + if (rdp->type_dependent2 == 0xffffffff) { + /* + * ioc is still writing to the reply post queue + * race condition - bail! + */ + printf("%s: ioc is writing a reply\n", DEVNAME(sc)); + continue; + } + smid = mpii_reply(sc, rdp); + + DNPRINTF(MPII_D_INTR, "%s: mpii_complete call to mpii_reply" + "returned: %d\n", DEVNAME(sc), smid); + + sc->sc_reply_post_host_index = + (sc->sc_reply_post_host_index + 1) % + sc->sc_reply_post_qdepth; } while (ccb->ccb_smid != smid); + mpii_write_reply_post(sc, sc->sc_reply_post_host_index); + return (0); } @@ -4850,27 +4905,6 @@ mpii_scsi_cmd(struct scsi_xfer *xs) if (ccb == NULL) return (NO_CCB); - /* XXX */ - if (sc->sc_mpii_dev[link->target] == NULL) { - DNPRINTF(MPII_D_MAP, "%s: mpii_scsi_cmd nonexistent tid %d\n", - DEVNAME(sc), link->target); - return (99); - } - - /* XXX */ - if (sc->sc_mpii_dev[link->target]->flags & MPII_DEV_UNUSED) { - DNPRINTF(MPII_D_MAP, "%s: mpii_scsi_cmd tid %d is " - "MPII_DEV_UNUSED\n", DEVNAME(sc), link->target); - return (99); - } - - /* XXX */ - if (sc->sc_mpii_dev[link->target]->flags & MPII_DEV_HIDDEN) { - DNPRINTF(MPII_D_MAP, "%s: mpii_scsi_cmd tid %d is " - "MPII_DEV_HIDDEN\n", DEVNAME(sc), link->target); - return (99); - } - DNPRINTF(MPII_D_CMD, "%s: ccb_smid: %d xs->flags: 0x%x\n", DEVNAME(sc), ccb->ccb_smid, xs->flags); @@ -4884,7 +4918,8 @@ mpii_scsi_cmd(struct scsi_xfer *xs) io->sense_buffer_length = sizeof(xs->sense); io->sgl_offset0 = 24; /* XXX fix this */ io->io_flags = htole16(xs->cmdlen); - io->dev_handle = htole16(sc->sc_mpii_dev[link->target]->dev_handle); + ccb->ccb_dev_handle = io->dev_handle = + htole16(sc->sc_mpii_dev[link->target]->dev_handle); io->lun[0] = htobe16(link->lun); switch (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) { @@ -4917,8 +4952,6 @@ mpii_scsi_cmd(struct scsi_xfer *xs) return (COMPLETE); } - timeout_set(&xs->stimeout, mpii_timeout_xs, ccb); - DNPRINTF(MPII_D_CMD, "%s: sizeof(mpii_msg_scsi_io): %d " "sizeof(mpii_ccb_bundle): %d sge offset: 0x%02x\n", DEVNAME(sc), sizeof(struct mpii_msg_scsi_io), @@ -4942,6 +4975,9 @@ mpii_scsi_cmd(struct scsi_xfer *xs) return (COMPLETE); } + timeout_set(&xs->stimeout, mpii_timeout_xs, ccb); + timeout_add(&xs->stimeout, (xs->timeout * 1000) / hz); + DNPRINTF(MPII_D_CMD, "%s: mpii_scsi_cmd(): opcode: %02x datalen: %d " "req_sense_len: %d\n", DEVNAME(sc), xs->cmd->opcode, xs->datalen, xs->req_sense_length); @@ -4969,7 +5005,8 @@ mpii_scsi_cmd_done(struct mpii_ccb *ccb) bus_dmamap_unload(sc->sc_dmat, dmap); } - /* timeout_del */ + if (!(xs->flags & SCSI_POLL)) + timeout_del(&xs->stimeout); xs->error = XS_NOERROR; xs->resid = 0; @@ -5040,6 +5077,8 @@ mpii_scsi_cmd_done(struct mpii_ccb *ccb) case MPII_IOCSTATUS_BUSY: case MPII_IOCSTATUS_INSUFFICIENT_RESOURCES: + case MPII_IOCSTATUS_SCSI_IOC_TERMINATED: + case MPII_IOCSTATUS_SCSI_TASK_TERMINATED: xs->error = XS_BUSY; break; @@ -5057,10 +5096,499 @@ mpii_scsi_cmd_done(struct mpii_ccb *ccb) bcopy(&mcb->mcb_sense, &xs->sense, sizeof(xs->sense)); - DNPRINTF(MPII_D_CMD, "%s: xs err: 0x%02x status: %d\n", DEVNAME(sc), + DNPRINTF(MPII_D_CMD, "%s: xs err: 0x%d status: %#x\n", DEVNAME(sc), xs->error, xs->status); mpii_push_reply(sc, ccb->ccb_rcb->rcb_reply_dva); mpii_put_ccb(sc, ccb); scsi_done(xs); } + +int +mpii_scsi_ioctl(struct scsi_link *link, u_long cmd, caddr_t addr, int flag, + struct proc *p) +{ + struct mpii_softc *sc = (struct mpii_softc *)link->adapter_softc; + + DNPRINTF(MPII_D_IOCTL, "%s: mpii_scsi_ioctl\n", DEVNAME(sc)); + + if (sc->sc_ioctl) + return (sc->sc_ioctl(link->adapter_softc, cmd, addr)); + else + return (ENOTTY); +} + +#if NBIO > 0 +int +mpii_ioctl(struct device *dev, u_long cmd, caddr_t addr) +{ + struct mpii_softc *sc = (struct mpii_softc *)dev; + int error = 0; + + DNPRINTF(MPII_D_IOCTL, "%s: mpii_ioctl ", DEVNAME(sc)); + + switch (cmd) { + case BIOCINQ: + DNPRINTF(MPII_D_IOCTL, "inq\n"); + error = mpii_ioctl_inq(sc, (struct bioc_inq *)addr); + break; + + case BIOCVOL: + DNPRINTF(MPII_D_IOCTL, "vol\n"); + error = mpii_ioctl_vol(sc, (struct bioc_vol *)addr); + break; + + case BIOCDISK: + DNPRINTF(MPII_D_IOCTL, "disk\n"); + error = mpii_ioctl_disk(sc, (struct bioc_disk *)addr); + break; + + default: + DNPRINTF(MPII_D_IOCTL, " invalid ioctl\n"); + error = EINVAL; + } + + return (error); +} + +int +mpii_ioctl_inq(struct mpii_softc *sc, struct bioc_inq *bi) +{ + DNPRINTF(MPII_D_IOCTL, "%s: mpii_ioctl_inq\n", DEVNAME(sc)); + + strlcpy(bi->bi_dev, DEVNAME(sc), sizeof(bi->bi_dev)); + + bi->bi_nodisk = sc->sc_pd_count; + bi->bi_novol = sc->sc_vd_count; + + return (0); +} + +int +mpii_ioctl_vol(struct mpii_softc *sc, struct bioc_vol *bv) +{ + struct mpii_cfg_raid_vol_pg0 *vpg; + struct mpii_cfg_hdr hdr; + struct scsi_link *lnk; + struct device *dev; + size_t pagelen; + u_int16_t volh; + int rv, hcnt = 0; + + DNPRINTF(MPII_D_IOCTL, "%s: mpii_ioctl_vol %d\n", + DEVNAME(sc), bv->bv_volid); + + if (bv->bv_volid > sc->sc_vd_count) + return (ENODEV); + + volh = sc->sc_mpii_dev[sc->sc_vd_id_low + bv->bv_volid]->dev_handle; + + if (mpii_req_cfg_header(sc, MPII_CONFIG_REQ_PAGE_TYPE_RAID_VOL, 0, + MPII_CFG_RAID_VOL_ADDR_HANDLE | volh, 0, &hdr) != 0) { + printf("%s: unable to fetch header for raid volume page 0\n", + DEVNAME(sc)); + return (EINVAL); + } + + pagelen = hdr.page_length * 4; + vpg = malloc(pagelen, M_TEMP, M_WAITOK | M_CANFAIL | M_ZERO); + if (vpg == NULL) { + printf("%s: unable to allocate space for raid " + "volume page 0\n", DEVNAME(sc)); + return (ENOMEM); + } + + if (mpii_req_cfg_page(sc, MPII_CFG_RAID_VOL_ADDR_HANDLE | volh, 0, + &hdr, 1, vpg, pagelen) != 0) { + printf("%s: unable to fetch raid volume page 0\n", + DEVNAME(sc)); + free(vpg, M_TEMP); + return (EINVAL); + } + + bv->bv_percent = -1; + + switch (vpg->volume_state) { + case MPII_CFG_RAID_VOL_0_STATE_ONLINE: + case MPII_CFG_RAID_VOL_0_STATE_OPTIMAL: + bv->bv_status = BIOC_SVONLINE; + break; + case MPII_CFG_RAID_VOL_0_STATE_DEGRADED: + bv->bv_status = BIOC_SVDEGRADED; + break; + case MPII_CFG_RAID_VOL_0_STATE_FAILED: + bv->bv_status = BIOC_SVOFFLINE; + break; + case MPII_CFG_RAID_VOL_0_STATE_INITIALIZING: + bv->bv_status = BIOC_SVBUILDING; + break; + case MPII_CFG_RAID_VOL_0_STATE_MISSING: + bv->bv_status = BIOC_SVINVALID; + break; + } + + switch (vpg->volume_type) { + case MPII_CFG_RAID_VOL_0_TYPE_RAID0: + bv->bv_level = 0; + break; + case MPII_CFG_RAID_VOL_0_TYPE_RAID1: + bv->bv_level = 1; + break; + case MPII_CFG_RAID_VOL_0_TYPE_RAID1E: + case MPII_CFG_RAID_VOL_0_TYPE_RAID10: + bv->bv_level = 10; + break; + default: + bv->bv_level = -1; + break; + } + + if ((rv = mpii_bio_hs(sc, NULL, 0, vpg->hot_spare_pool, &hcnt)) != 0) { + free(vpg, M_TEMP); + return (rv); + } + + bv->bv_nodisk = vpg->num_phys_disks + hcnt; + + bv->bv_size = letoh64(vpg->max_lba) * letoh16(vpg->block_size); + + lnk = sc->sc_scsibus->sc_link[bv->bv_volid][0]; + if (lnk != NULL) { + dev = lnk->device_softc; + strlcpy(bv->bv_dev, dev->dv_xname, sizeof(bv->bv_dev)); + } + + free(vpg, M_TEMP); + return (0); +} + +int +mpii_ioctl_disk(struct mpii_softc *sc, struct bioc_disk *bd) +{ + struct mpii_cfg_raid_vol_pg0 *vpg; + struct mpii_cfg_raid_vol_pg0_physdisk *pd; + struct mpii_cfg_hdr hdr; + size_t pagelen; + u_int16_t volh; + u_int8_t dn; + + DNPRINTF(MPII_D_IOCTL, "%s: mpii_ioctl_disk %d/%d\n", + DEVNAME(sc), bd->bd_volid, bd->bd_diskid); + + if (bd->bd_volid > sc->sc_vd_count) + return (ENODEV); + + volh = sc->sc_mpii_dev[sc->sc_vd_id_low + bd->bd_volid]->dev_handle; + + if (mpii_req_cfg_header(sc, MPII_CONFIG_REQ_PAGE_TYPE_RAID_VOL, 0, + MPII_CFG_RAID_VOL_ADDR_HANDLE | volh, 0, &hdr) != 0) { + printf("%s: unable to fetch header for raid volume page 0\n", + DEVNAME(sc)); + return (EINVAL); + } + + pagelen = hdr.page_length * 4; + vpg = malloc(pagelen, M_TEMP, M_WAITOK | M_CANFAIL | M_ZERO); + if (vpg == NULL) { + printf("%s: unable to allocate space for raid " + "volume page 0\n", DEVNAME(sc)); + return (ENOMEM); + } + + if (mpii_req_cfg_page(sc, MPII_CFG_RAID_VOL_ADDR_HANDLE | volh, 0, + &hdr, 1, vpg, pagelen) != 0) { + printf("%s: unable to fetch raid volume page 0\n", + DEVNAME(sc)); + free(vpg, M_TEMP); + return (EINVAL); + } + + if (bd->bd_diskid >= vpg->num_phys_disks) { + u_int8_t hsmap = vpg->hot_spare_pool; + + free(vpg, M_TEMP); + return (mpii_bio_hs(sc, bd, vpg->num_phys_disks, hsmap, NULL)); + } + + pd = (struct mpii_cfg_raid_vol_pg0_physdisk *)(vpg + 1) + + bd->bd_diskid; + dn = pd->phys_disk_num; + + free(vpg, M_TEMP); + return (mpii_bio_disk(sc, bd, dn)); +} + +int +mpii_bio_hs(struct mpii_softc *sc, struct bioc_disk *bd, int nvdsk, + u_int8_t hsmap, int *hscnt) +{ + struct mpii_cfg_raid_config_pg0 *cpg; + struct mpii_raid_config_element *el; + struct mpii_ecfg_hdr ehdr; + size_t pagelen; + int i, nhs = 0; + + if (bd) + DNPRINTF(MPII_D_IOCTL, "%s: mpii_bio_hs %d\n", DEVNAME(sc), + bd->bd_diskid - nvdsk); + else + DNPRINTF(MPII_D_IOCTL, "%s: mpii_bio_hs\n", DEVNAME(sc)); + + if (mpii_req_cfg_header(sc, MPII_CONFIG_REQ_PAGE_TYPE_RAID_CONFIG, + 0, MPII_CFG_RAID_CONFIG_ACTIVE_CONFIG, MPII_PG_EXTENDED, + &ehdr) != 0) { + printf("%s: unable to fetch header for raid config page 0\n", + DEVNAME(sc)); + return (EINVAL); + } + + pagelen = ehdr.ext_page_length * 4; + cpg = malloc(pagelen, M_TEMP, M_WAITOK | M_CANFAIL | M_ZERO); + if (cpg == NULL) { + printf("%s: unable to allocate space for raid config page 0\n", + DEVNAME(sc)); + return (ENOMEM); + } + + if (mpii_req_cfg_page(sc, MPII_CFG_RAID_CONFIG_ACTIVE_CONFIG, + MPII_PG_EXTENDED, &ehdr, 1, cpg, pagelen) != 0) { + printf("%s: unable to fetch raid config page 0\n", + DEVNAME(sc)); + free(cpg, M_TEMP); + return (ENXIO); + } + + el = (struct mpii_raid_config_element *)(cpg + 1); + for (i = 0; i < cpg->num_elements; i++, el++) { + if (ISSET(el->element_flags, + MPII_RAID_CONFIG_ELEMENT_FLAG_HSP_PHYS_DISK) && + el->hot_spare_pool == hsmap) { + /* + * diskid comparison is based on the idea that all + * disks are counted by the bio(4) in sequence, thus + * substracting the number of disks in the volume + * from the diskid yields us a "relative" hotspare + * number, which is good enough for us. + */ + if (bd != NULL && bd->bd_diskid == nhs + nvdsk) { + free(cpg, M_TEMP); + return (mpii_bio_disk(sc, bd, + el->phys_disk_num)); + } + nhs++; + } + } + + if (hscnt) + *hscnt = nhs; + + free(cpg, M_TEMP); + return (0); +} + +int +mpii_bio_disk(struct mpii_softc *sc, struct bioc_disk *bd, u_int8_t dn) +{ + struct mpii_cfg_raid_physdisk_pg0 ppg; + struct mpii_cfg_hdr hdr; + + DNPRINTF(MPII_D_IOCTL, "%s: mpii_bio_disk %d\n", + DEVNAME(sc), bd->bd_diskid); + + if (bd->bd_volid > sc->sc_vd_count) + return (ENODEV); + + hdr.page_version = 0; + hdr.page_length = sizeof(ppg) / 4; + hdr.page_number = 0; + hdr.page_type = MPII_CONFIG_REQ_PAGE_TYPE_RAID_PD; + + if (mpii_req_cfg_page(sc, MPII_CFG_RAID_PHYS_DISK_ADDR_NUMBER | dn, 0, + &hdr, 1, &ppg, sizeof(ppg)) != 0) { + printf("%s: unable to fetch raid drive page 0\n", + DEVNAME(sc)); + return (EINVAL); + } + + bd->bd_channel = ppg.phys_disk_bus; + bd->bd_target = ppg.phys_disk_num; + + switch (ppg.phys_disk_state) { + case MPII_CFG_RAID_PHYDISK_0_STATE_ONLINE: + case MPII_CFG_RAID_PHYDISK_0_STATE_OPTIMAL: + bd->bd_status = BIOC_SDONLINE; + break; + case MPII_CFG_RAID_PHYDISK_0_STATE_OFFLINE: + bd->bd_status = BIOC_SDOFFLINE; + break; + case MPII_CFG_RAID_PHYDISK_0_STATE_DEGRADED: + bd->bd_status = BIOC_SDFAILED; + break; + case MPII_CFG_RAID_PHYDISK_0_STATE_REBUILDING: + bd->bd_status = BIOC_SDREBUILD; + break; + case MPII_CFG_RAID_PHYDISK_0_STATE_HOTSPARE: + bd->bd_status = BIOC_SDHOTSPARE; + break; + case MPII_CFG_RAID_PHYDISK_0_STATE_NOTCONFIGURED: + bd->bd_status = BIOC_SDUNUSED; + break; + case MPII_CFG_RAID_PHYDISK_0_STATE_NOTCOMPATIBLE: + bd->bd_status = BIOC_SDINVALID; + break; + } + + bd->bd_size = letoh64(ppg.dev_max_lba) * letoh16(ppg.block_size); + + scsi_strvis(bd->bd_vendor, ppg.product_id, sizeof(ppg.product_id)); + scsi_strvis(bd->bd_serial, ppg.serial, sizeof(ppg.serial)); + + return (0); +} + +#ifndef SMALL_KERNEL +int +mpii_bio_volstate(struct mpii_softc *sc, struct bioc_vol *bv) +{ + struct mpii_cfg_raid_vol_pg0 *vpg; + struct mpii_cfg_hdr hdr; + size_t pagelen; + u_int16_t volh; + + DNPRINTF(MPII_D_IOCTL, "%s: mpii_ioctl_vol %d\n", + DEVNAME(sc), bv->bv_volid); + + if (bv->bv_volid > sc->sc_vd_count) + return (ENODEV); + + volh = sc->sc_mpii_dev[sc->sc_vd_id_low + bv->bv_volid]->dev_handle; + + if (mpii_cfg_header(sc, MPII_CONFIG_REQ_PAGE_TYPE_RAID_VOL, 0, + MPII_CFG_RAID_VOL_ADDR_HANDLE | volh, &hdr) != 0) { + printf("%s: unable to fetch header for raid volume page 0\n", + DEVNAME(sc)); + return (EINVAL); + } + + pagelen = hdr.page_length * 4; + vpg = malloc(pagelen, M_TEMP, M_NOWAIT | M_CANFAIL | M_ZERO); + if (vpg == NULL) { + printf("%s: unable to allocate space for raid " + "volume page 0\n", DEVNAME(sc)); + return (ENOMEM); + } + + if (mpii_cfg_page(sc, MPII_CFG_RAID_VOL_ADDR_HANDLE | volh, + &hdr, 1, vpg, pagelen) != 0) { + printf("%s: unable to fetch raid volume page 0\n", + DEVNAME(sc)); + free(vpg, M_TEMP); + return (EINVAL); + } + + switch (vpg->volume_state) { + case MPII_CFG_RAID_VOL_0_STATE_ONLINE: + case MPII_CFG_RAID_VOL_0_STATE_OPTIMAL: + bv->bv_status = BIOC_SVONLINE; + break; + case MPII_CFG_RAID_VOL_0_STATE_DEGRADED: + bv->bv_status = BIOC_SVDEGRADED; + break; + case MPII_CFG_RAID_VOL_0_STATE_FAILED: + bv->bv_status = BIOC_SVOFFLINE; + break; + case MPII_CFG_RAID_VOL_0_STATE_INITIALIZING: + bv->bv_status = BIOC_SVBUILDING; + break; + case MPII_CFG_RAID_VOL_0_STATE_MISSING: + bv->bv_status = BIOC_SVINVALID; + break; + } + + free(vpg, M_TEMP); + return (0); +} + +int +mpii_create_sensors(struct mpii_softc *sc) +{ + struct scsibus_softc *ssc = sc->sc_scsibus; + struct device *dev; + int i; + + sc->sc_sensors = malloc(sizeof(struct ksensor) * sc->sc_vd_count, + M_DEVBUF, M_WAITOK | M_ZERO); + if (sc->sc_sensors == NULL) + return (1); + + strlcpy(sc->sc_sensordev.xname, DEVNAME(sc), + sizeof(sc->sc_sensordev.xname)); + + for (i = 0; i < sc->sc_vd_count; i++) { + if (ssc->sc_link[i][0] == NULL) + goto bad; + + dev = ssc->sc_link[i][0]->device_softc; + + sc->sc_sensors[i].type = SENSOR_DRIVE; + sc->sc_sensors[i].status = SENSOR_S_UNKNOWN; + + strlcpy(sc->sc_sensors[i].desc, dev->dv_xname, + sizeof(sc->sc_sensors[i].desc)); + + sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]); + } + + if (sensor_task_register(sc, mpii_refresh_sensors, 10) == NULL) + goto bad; + + sensordev_install(&sc->sc_sensordev); + + return (0); + +bad: + free(sc->sc_sensors, M_DEVBUF); + + return (1); +} + +void +mpii_refresh_sensors(void *arg) +{ + struct mpii_softc *sc = arg; + struct bioc_vol bv; + int i; + + for (i = 0; i < sc->sc_vd_count; i++) { + bzero(&bv, sizeof(bv)); + bv.bv_volid = i; + if (mpii_bio_volstate(sc, &bv)) + return; + + switch(bv.bv_status) { + case BIOC_SVOFFLINE: + sc->sc_sensors[i].value = SENSOR_DRIVE_FAIL; + sc->sc_sensors[i].status = SENSOR_S_CRIT; + break; + + case BIOC_SVDEGRADED: + sc->sc_sensors[i].value = SENSOR_DRIVE_PFAIL; + sc->sc_sensors[i].status = SENSOR_S_WARN; + break; + + case BIOC_SVSCRUB: + case BIOC_SVONLINE: + sc->sc_sensors[i].value = SENSOR_DRIVE_ONLINE; + sc->sc_sensors[i].status = SENSOR_S_OK; + break; + + case BIOC_SVINVALID: + /* FALLTRHOUGH */ + default: + sc->sc_sensors[i].value = 0; /* unknown */ + sc->sc_sensors[i].status = SENSOR_S_UNKNOWN; + } + } +} +#endif /* SMALL_KERNEL */ +#endif /* NBIO > 0 */ |