this diff implements the disk cache ioctl handling in mpii so sd(4) can drive the change rather than have mpii(4) whack everything. modelled on the same functionality in mpi(4) and mikeb's code...
could someone test this please? Index: mpii.c =================================================================== RCS file: /cvs/src/sys/dev/pci/mpii.c,v retrieving revision 1.37 diff -u -p -r1.37 mpii.c --- mpii.c 29 Dec 2010 03:55:09 -0000 1.37 +++ mpii.c 18 Feb 2011 06:54:58 -0000 @@ -29,6 +29,7 @@ #include <sys/kernel.h> #include <sys/rwlock.h> #include <sys/sensors.h> +#include <sys/dkio.h> #include <sys/tree.h> #include <machine/bus.h> @@ -981,6 +982,52 @@ struct mpii_msg_sas_oper_reply { u_int32_t ioc_loginfo; } __packed; +struct mpii_msg_raid_action_request { + u_int8_t action; +#define MPII_RAID_ACTION_CHANGE_VOL_WRITE_CACHE (0x17) + u_int8_t reserved1; + u_int8_t chain_offset; + u_int8_t function; + + u_int16_t vol_dev_handle; + u_int8_t phys_disk_num; + u_int8_t msg_flags; + + u_int8_t vp_id; + u_int8_t vf_if; + u_int16_t reserved2; + + u_int32_t reserved3; + + u_int32_t action_data; +#define MPII_RAID_VOL_WRITE_CACHE_DISABLE (0x01) +#define MPII_RAID_VOL_WRITE_CACHE_ENABLE (0x02) + + struct mpii_sge action_sge; +} __packed; + +struct mpii_msg_raid_action_reply { + u_int8_t action; + u_int8_t reserved1; + u_int8_t chain_offset; + u_int8_t function; + + u_int16_t vol_dev_handle; + u_int8_t phys_disk_num; + u_int8_t msg_flags; + + u_int8_t vp_id; + u_int8_t vf_if; + u_int16_t reserved2; + + u_int16_t reserved3; + u_int16_t ioc_status; + + u_int32_t action_data[5]; + + struct mpii_sge action_sge; +} __packed; + struct mpii_cfg_hdr { u_int8_t page_version; u_int8_t page_length; @@ -1256,6 +1303,11 @@ struct mpii_cfg_raid_vol_pg0 { #define MPII_CFG_RAID_VOL_0_STATUS_RESYNC (1<<16) u_int16_t volume_settings; +#define MPII_CFG_RAID_VOL_0_SETTINGS_CACHE_MASK (0x3<<0) +#define MPII_CFG_RAID_VOL_0_SETTINGS_CACHE_UNCHANGED (0x0<<0) +#define MPII_CFG_RAID_VOL_0_SETTINGS_CACHE_DISABLED (0x1<<0) +#define MPII_CFG_RAID_VOL_0_SETTINGS_CACHE_ENABLED (0x2<<0) + u_int8_t hot_spare_pool; u_int8_t reserved1; @@ -1972,6 +2024,8 @@ int mpii_req_cfg_page(struct mpii_softc int mpii_get_ioc_pg8(struct mpii_softc *); +int mpii_ioctl_cache(struct scsi_link *, u_long, struct dk_cache *); + #if NBIO > 0 int mpii_ioctl(struct device *, u_long, caddr_t); int mpii_ioctl_inq(struct mpii_softc *, struct bioc_inq *); @@ -4650,19 +4704,113 @@ mpii_scsi_cmd_done(struct mpii_ccb *ccb) mpii_push_reply(sc, ccb->ccb_rcb); scsi_done(xs); -} +} int mpii_scsi_ioctl(struct scsi_link *link, u_long cmd, caddr_t addr, int flag) { struct mpii_softc *sc = (struct mpii_softc *)link->adapter_softc; + struct mpii_device *dev = sc->sc_devs[link->target]; 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); + switch (cmd) { + case DIOCGCACHE: + case DIOCSCACHE: + if (dev != NULL && ISSET(dev->flags, MPII_DF_VOLUME)) { + return (mpii_ioctl_cache(link, cmd, + (struct dk_cache *)addr)); + } + break; + + default: + if (sc->sc_ioctl) + return (sc->sc_ioctl(link->adapter_softc, cmd, addr)); + + break; + } + + return (ENOTTY); +} + +int +mpii_ioctl_cache(struct scsi_link *link, u_long cmd, struct dk_cache *dc) +{ + struct mpii_softc *sc = (struct mpii_softc *)link->adapter_softc; + struct mpii_device *dev = sc->sc_devs[link->target]; + struct mpii_cfg_raid_vol_pg0 *vpg; + struct mpii_msg_raid_action_request *req; + struct mpii_cfg_hdr hdr; + struct mpii_ccb *ccb; + u_int32_t addr = MPII_CFG_RAID_VOL_ADDR_HANDLE | dev->dev_handle; + size_t pagelen; + int rv = 0; + int enabled; + + if (mpii_req_cfg_header(sc, MPII_CONFIG_REQ_PAGE_TYPE_RAID_VOL, 0, + addr, 0, &hdr) != 0) + return (EINVAL); + + pagelen = hdr.page_length * 4; + vpg = malloc(pagelen, M_TEMP, M_WAITOK | M_CANFAIL | M_ZERO); + if (vpg == NULL) + return (ENOMEM); + + if (mpii_req_cfg_page(sc, addr, 0, &hdr, 1, vpg, pagelen) != 0) { + rv = EINVAL; + goto done; + free(vpg, M_TEMP); + return (EINVAL); + } + + enabled = ((letoh16(vpg->volume_settings) & + MPII_CFG_RAID_VOL_0_SETTINGS_CACHE_MASK) == + MPII_CFG_RAID_VOL_0_SETTINGS_CACHE_ENABLED) ? 1 : 0; + + if (cmd == DIOCGCACHE) { + dc->wrcache = enabled; + dc->rdcache = 0; + goto done; + } /* else DIOCSCACHE */ + + if (dc->rdcache) { + rv = EOPNOTSUPP; + goto done; + } + + if (((dc->wrcache) ? 1 : 0) == enabled) + goto done; + + ccb = scsi_io_get(&sc->sc_iopool, 0); + if (ccb == NULL) { + rv = ENOMEM; + goto done; + } + + ccb->ccb_done = mpii_empty_done; + + req = ccb->ccb_cmd; + bzero(req, sizeof(*req)); + req->function = MPII_FUNCTION_RAID_ACTION; + req->action = MPII_RAID_ACTION_CHANGE_VOL_WRITE_CACHE; + req->vol_dev_handle = htole16(dev->dev_handle); + req->action_data = htole32(dc->wrcache ? + MPII_RAID_VOL_WRITE_CACHE_ENABLE : + MPII_RAID_VOL_WRITE_CACHE_DISABLE); + + if (mpii_poll(sc, ccb) != 0) { + rv = EIO; + goto done; + } + + if (ccb->ccb_rcb != NULL) + mpii_push_reply(sc, ccb->ccb_rcb); + + scsi_io_put(&sc->sc_iopool, ccb); + +done: + free(vpg, M_TEMP); + return (rv); } #if NBIO > 0