Module Name: src Committed By: jmcneill Date: Sat Sep 27 16:14:16 UTC 2014
Modified Files: src/sys/dev/ic: mpt.c mpt.h mpt_netbsd.c Log Message: add bio(4) support To generate a diff of this commit: cvs rdiff -u -r1.16 -r1.17 src/sys/dev/ic/mpt.c cvs rdiff -u -r1.7 -r1.8 src/sys/dev/ic/mpt.h cvs rdiff -u -r1.25 -r1.26 src/sys/dev/ic/mpt_netbsd.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/ic/mpt.c diff -u src/sys/dev/ic/mpt.c:1.16 src/sys/dev/ic/mpt.c:1.17 --- src/sys/dev/ic/mpt.c:1.16 Sun Mar 18 21:05:21 2012 +++ src/sys/dev/ic/mpt.c Sat Sep 27 16:14:16 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: mpt.c,v 1.16 2012/03/18 21:05:21 martin Exp $ */ +/* $NetBSD: mpt.c,v 1.17 2014/09/27 16:14:16 jmcneill Exp $ */ /* * Copyright (c) 2000, 2001 by Greg Ansley @@ -110,7 +110,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: mpt.c,v 1.16 2012/03/18 21:05:21 martin Exp $"); +__KERNEL_RCSID(0, "$NetBSD: mpt.c,v 1.17 2014/09/27 16:14:16 jmcneill Exp $"); #include <dev/ic/mpt.h> @@ -565,10 +565,7 @@ mpt_send_ioc_init(mpt_softc_t *mpt, u_in * Utiltity routine to read configuration headers and pages */ -static int -mpt_read_cfg_header(mpt_softc_t *, int, int, int, fCONFIG_PAGE_HEADER *); - -static int +int mpt_read_cfg_header(mpt_softc_t *mpt, int PageType, int PageNumber, int PageAddress, fCONFIG_PAGE_HEADER *rslt) { @@ -1516,4 +1513,10 @@ mpt2host_config_page_raid_phys_disk_0(fC MPT_2_HOST16(rpd0, ErrorData.SmartCount); } +void +mpt2host_config_page_ioc_2(fCONFIG_PAGE_IOC_2 *ioc2) +{ + MPT_2_HOST32(ioc2, CapabilitiesFlags); +} + #endif Index: src/sys/dev/ic/mpt.h diff -u src/sys/dev/ic/mpt.h:1.7 src/sys/dev/ic/mpt.h:1.8 --- src/sys/dev/ic/mpt.h:1.7 Wed Apr 28 22:45:27 2010 +++ src/sys/dev/ic/mpt.h Sat Sep 27 16:14:16 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: mpt.h,v 1.7 2010/04/28 22:45:27 chs Exp $ */ +/* $NetBSD: mpt.h,v 1.8 2014/09/27 16:14:16 jmcneill Exp $ */ /* * Copyright (c) 2000, 2001 by Greg Ansley @@ -173,6 +173,7 @@ void mpt_free_request(mpt_softc_t *, req int mpt_intr(void *); void mpt_check_doorbell(mpt_softc_t *); +int mpt_read_cfg_header(mpt_softc_t *, int, int, int, fCONFIG_PAGE_HEADER *); int mpt_read_cfg_page(mpt_softc_t *, int, fCONFIG_PAGE_HEADER *); int mpt_write_cfg_page(mpt_softc_t *, int, fCONFIG_PAGE_HEADER *); @@ -212,6 +213,8 @@ void mpt2host_config_page_fc_port_1(fCON void host2mpt_config_page_fc_port_1(fCONFIG_PAGE_FC_PORT_1 *); void mpt2host_config_page_raid_vol_0(fCONFIG_PAGE_RAID_VOL_0 *); void mpt2host_config_page_raid_phys_disk_0(fCONFIG_PAGE_RAID_PHYS_DISK_0 *); +void mpt2host_config_page_raid_phys_disk_0(fCONFIG_PAGE_RAID_PHYS_DISK_0 *); +void mpt2host_config_page_ioc_2(fCONFIG_PAGE_IOC_2 *); #else #define mpt2host_sge_simple_union(x) do { ; } while (0) #define mpt2host_iocfacts_reply(x) do { ; } while (0) @@ -230,6 +233,7 @@ void mpt2host_config_page_raid_phys_disk #define mpt2host_config_page_raid_vol_0(x) do { ; } while (0) #define mpt2host_config_page_raid_phys_disk_0(x) \ do { ; } while (0) +#define mpt2host_config_page_ioc_2(x) do { ; } while (0) #endif #endif /* _KERNEL */ Index: src/sys/dev/ic/mpt_netbsd.c diff -u src/sys/dev/ic/mpt_netbsd.c:1.25 src/sys/dev/ic/mpt_netbsd.c:1.26 --- src/sys/dev/ic/mpt_netbsd.c:1.25 Tue Jul 8 14:18:54 2014 +++ src/sys/dev/ic/mpt_netbsd.c Sat Sep 27 16:14:16 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: mpt_netbsd.c,v 1.25 2014/07/08 14:18:54 chs Exp $ */ +/* $NetBSD: mpt_netbsd.c,v 1.26 2014/09/27 16:14:16 jmcneill Exp $ */ /* * Copyright (c) 2003 Wasabi Systems, Inc. @@ -77,11 +77,17 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: mpt_netbsd.c,v 1.25 2014/07/08 14:18:54 chs Exp $"); +__KERNEL_RCSID(0, "$NetBSD: mpt_netbsd.c,v 1.26 2014/09/27 16:14:16 jmcneill Exp $"); + +#include "bio.h" #include <dev/ic/mpt.h> /* pulls in all headers */ #include <sys/scsiio.h> +#if NBIO > 0 +#include <dev/biovar.h> +#endif + static int mpt_poll(mpt_softc_t *, struct scsipi_xfer *, int); static void mpt_timeout(void *); static void mpt_restart(mpt_softc_t *, request_t *); @@ -100,6 +106,15 @@ static void mpt_minphys(struct buf *); static int mpt_ioctl(struct scsipi_channel *, u_long, void *, int, struct proc *); +#if NBIO > 0 +static bool mpt_is_raid(mpt_softc_t *); +static int mpt_bio_ioctl(device_t, u_long, void *); +static int mpt_bio_ioctl_inq(mpt_softc_t *, struct bioc_inq *); +static int mpt_bio_ioctl_vol(mpt_softc_t *, struct bioc_vol *); +static int mpt_bio_ioctl_disk(mpt_softc_t *, struct bioc_disk *); +static int mpt_bio_ioctl_setstate(mpt_softc_t *, struct bioc_setstate *); +#endif + void mpt_scsipi_attach(mpt_softc_t *mpt) { @@ -144,6 +159,14 @@ mpt_scsipi_attach(mpt_softc_t *mpt) */ mpt->sc_scsibus_dv = config_found(mpt->sc_dev, &mpt->sc_channel, scsiprint); + +#if NBIO > 0 + if (mpt_is_raid(mpt)) { + if (bio_register(mpt->sc_dev, mpt_bio_ioctl) != 0) + panic("%s: controller registration failed", + device_xname(mpt->sc_dev)); + } +#endif } int @@ -1585,3 +1608,317 @@ mpt_ioctl(struct scsipi_channel *chan, u return (ENOTTY); } } + +#if NBIO > 0 +static fCONFIG_PAGE_IOC_2 * +mpt_get_cfg_page_ioc2(mpt_softc_t *mpt) +{ + fCONFIG_PAGE_HEADER hdr; + fCONFIG_PAGE_IOC_2 *ioc2; + int rv; + + rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_IOC, 2, 0, &hdr); + if (rv) + return NULL; + + ioc2 = malloc(hdr.PageLength * 4, M_DEVBUF, M_WAITOK | M_ZERO); + if (ioc2 == NULL) + return NULL; + + memcpy(ioc2, &hdr, sizeof(hdr)); + + rv = mpt_read_cfg_page(mpt, 0, &ioc2->Header); + if (rv) + goto fail; + mpt2host_config_page_ioc_2(ioc2); + + return ioc2; + +fail: + free(ioc2, M_DEVBUF); + return NULL; +} + +static fCONFIG_PAGE_RAID_VOL_0 * +mpt_get_cfg_page_raid_vol0(mpt_softc_t *mpt, int address) +{ + fCONFIG_PAGE_HEADER hdr; + fCONFIG_PAGE_RAID_VOL_0 *rvol0; + int rv; + + rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_RAID_VOLUME, 0, + address, &hdr); + if (rv) + return NULL; + + rvol0 = malloc(hdr.PageLength * 4, M_DEVBUF, M_WAITOK | M_ZERO); + if (rvol0 == NULL) + return NULL; + + memcpy(rvol0, &hdr, sizeof(hdr)); + + rv = mpt_read_cfg_page(mpt, address, &rvol0->Header); + if (rv) + goto fail; + mpt2host_config_page_raid_vol_0(rvol0); + + return rvol0; + +fail: + free(rvol0, M_DEVBUF); + return NULL; +} + +static fCONFIG_PAGE_RAID_PHYS_DISK_0 * +mpt_get_cfg_page_raid_phys_disk0(mpt_softc_t *mpt, int address) +{ + fCONFIG_PAGE_HEADER hdr; + fCONFIG_PAGE_RAID_PHYS_DISK_0 *physdisk0; + int rv; + + rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_RAID_PHYSDISK, 0, + address, &hdr); + if (rv) + return NULL; + + physdisk0 = malloc(hdr.PageLength * 4, M_DEVBUF, M_WAITOK | M_ZERO); + if (physdisk0 == NULL) + return NULL; + + memcpy(physdisk0, &hdr, sizeof(hdr)); + + rv = mpt_read_cfg_page(mpt, address, &physdisk0->Header); + if (rv) + goto fail; + mpt2host_config_page_raid_phys_disk_0(physdisk0); + + return physdisk0; + +fail: + free(physdisk0, M_DEVBUF); + return NULL; +} + +static bool +mpt_is_raid(mpt_softc_t *mpt) +{ + fCONFIG_PAGE_IOC_2 *ioc2; + bool is_raid = false; + + ioc2 = mpt_get_cfg_page_ioc2(mpt); + if (ioc2 == NULL) + return false; + + if (ioc2->CapabilitiesFlags != 0xdeadbeef) { + is_raid = !!(ioc2->CapabilitiesFlags & + (MPI_IOCPAGE2_CAP_FLAGS_IS_SUPPORT| + MPI_IOCPAGE2_CAP_FLAGS_IME_SUPPORT| + MPI_IOCPAGE2_CAP_FLAGS_IM_SUPPORT)); + } + + free(ioc2, M_DEVBUF); + + return is_raid; +} + +static int +mpt_bio_ioctl(device_t dev, u_long cmd, void *addr) +{ + mpt_softc_t *mpt = device_private(dev); + int error, s; + + KERNEL_LOCK(1, curlwp); + s = splbio(); + + switch (cmd) { + case BIOCINQ: + error = mpt_bio_ioctl_inq(mpt, addr); + break; + case BIOCVOL: + error = mpt_bio_ioctl_vol(mpt, addr); + break; + case BIOCDISK: + error = mpt_bio_ioctl_disk(mpt, addr); + break; + case BIOCSETSTATE: + error = mpt_bio_ioctl_setstate(mpt, addr); + break; + default: + error = EINVAL; + break; + } + + splx(s); + KERNEL_UNLOCK_ONE(curlwp); + + return error; +} + +static int +mpt_bio_ioctl_inq(mpt_softc_t *mpt, struct bioc_inq *bi) +{ + fCONFIG_PAGE_IOC_2 *ioc2; + + ioc2 = mpt_get_cfg_page_ioc2(mpt); + if (ioc2 == NULL) + return EIO; + + strlcpy(bi->bi_dev, device_xname(mpt->sc_dev), sizeof(bi->bi_dev)); + bi->bi_novol = ioc2->NumActiveVolumes; + bi->bi_nodisk = ioc2->NumActivePhysDisks; + + free(ioc2, M_DEVBUF); + + return 0; +} + +static int +mpt_bio_ioctl_vol(mpt_softc_t *mpt, struct bioc_vol *bv) +{ + fCONFIG_PAGE_IOC_2 *ioc2 = NULL; + fCONFIG_PAGE_IOC_2_RAID_VOL *ioc2rvol; + fCONFIG_PAGE_RAID_VOL_0 *rvol0 = NULL; + int address; + + ioc2 = mpt_get_cfg_page_ioc2(mpt); + if (ioc2 == NULL) + return EIO; + + if (bv->bv_volid < 0 || bv->bv_volid >= ioc2->NumActiveVolumes) + goto fail; + + ioc2rvol = &ioc2->RaidVolume[bv->bv_volid]; + address = ioc2rvol->VolumeID | (ioc2rvol->VolumeBus << 8); + + rvol0 = mpt_get_cfg_page_raid_vol0(mpt, address); + if (rvol0 == NULL) + goto fail; + + strlcpy(bv->bv_dev, device_xname(mpt->sc_dev), sizeof(bv->bv_dev)); + /* TODO: bv->bv_vendor */ + bv->bv_nodisk = rvol0->NumPhysDisks; + bv->bv_size = (uint64_t)rvol0->MaxLBA * 512; + bv->bv_stripe_size = rvol0->StripeSize; + bv->bv_percent = -1; + bv->bv_seconds = 0; + + switch (rvol0->VolumeStatus.State) { + case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL: + bv->bv_status = BIOC_SVONLINE; + break; + case MPI_RAIDVOL0_STATUS_STATE_DEGRADED: + bv->bv_status = BIOC_SVDEGRADED; + break; + case MPI_RAIDVOL0_STATUS_STATE_FAILED: + bv->bv_status = BIOC_SVOFFLINE; + break; + default: + bv->bv_status = BIOC_SVINVALID; + break; + } + + switch (ioc2rvol->VolumeType) { + case MPI_RAID_VOL_TYPE_IS: + bv->bv_level = 0; + break; + case MPI_RAID_VOL_TYPE_IME: + case MPI_RAID_VOL_TYPE_IM: + bv->bv_level = 1; + break; + default: + bv->bv_level = -1; + break; + } + + free(ioc2, M_DEVBUF); + free(rvol0, M_DEVBUF); + + return 0; + +fail: + if (ioc2) free(ioc2, M_DEVBUF); + if (rvol0) free(rvol0, M_DEVBUF); + return EINVAL; +} + +static int +mpt_bio_ioctl_disk(mpt_softc_t *mpt, struct bioc_disk *bd) +{ + fCONFIG_PAGE_IOC_2 *ioc2 = NULL; + fCONFIG_PAGE_RAID_VOL_0 *rvol0 = NULL; + fCONFIG_PAGE_IOC_2_RAID_VOL *ioc2rvol; + fCONFIG_PAGE_RAID_PHYS_DISK_0 *phys = NULL; + int address; + + ioc2 = mpt_get_cfg_page_ioc2(mpt); + if (ioc2 == NULL) + return EIO; + + if (bd->bd_volid < 0 || bd->bd_volid >= ioc2->NumActiveVolumes) + goto fail; + + ioc2rvol = &ioc2->RaidVolume[bd->bd_volid]; + address = ioc2rvol->VolumeID | (ioc2rvol->VolumeBus << 8); + + rvol0 = mpt_get_cfg_page_raid_vol0(mpt, address); + if (rvol0 == NULL) + goto fail; + + if (bd->bd_diskid < 0 || bd->bd_diskid >= rvol0->NumPhysDisks) + goto fail; + + address = rvol0->PhysDisk[bd->bd_diskid].PhysDiskNum; + + phys = mpt_get_cfg_page_raid_phys_disk0(mpt, address); + if (phys == NULL) + goto fail; + + bd->bd_channel = phys->PhysDiskBus; + bd->bd_target = phys->PhysDiskID; + bd->bd_lun = 0; + bd->bd_size = (uint64_t)phys->MaxLBA * 512; + strlcpy(bd->bd_vendor, phys->InquiryData.VendorID, + min(sizeof(bd->bd_vendor), sizeof(phys->InquiryData.VendorID))); + strlcpy(bd->bd_serial, phys->InquiryData.Info, sizeof(bd->bd_serial)); + bd->bd_procdev[0] = '\0'; + + switch (phys->PhysDiskStatus.State) { + case MPI_PHYSDISK0_STATUS_ONLINE: + bd->bd_status = BIOC_SDONLINE; + break; + case MPI_PHYSDISK0_STATUS_MISSING: + case MPI_PHYSDISK0_STATUS_FAILED: + bd->bd_status = BIOC_SDFAILED; + break; + case MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED: + case MPI_PHYSDISK0_STATUS_FAILED_REQUESTED: + case MPI_PHYSDISK0_STATUS_OTHER_OFFLINE: + bd->bd_status = BIOC_SDOFFLINE; + break; + case MPI_PHYSDISK0_STATUS_INITIALIZING: + bd->bd_status = BIOC_SDSCRUB; + break; + case MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE: + default: + bd->bd_status = BIOC_SDINVALID; + break; + } + + free(ioc2, M_DEVBUF); + free(phys, M_DEVBUF); + + return 0; + +fail: + if (ioc2) free(ioc2, M_DEVBUF); + if (phys) free(phys, M_DEVBUF); + return EINVAL; +} + +static int +mpt_bio_ioctl_setstate(mpt_softc_t *mpt, struct bioc_setstate *bs) +{ + return ENOTTY; +} +#endif +