1 1.56 msaitoh /* $NetBSD: ciss.c,v 1.56 2024/02/19 14:54:04 msaitoh Exp $ */ 2 1.30 christos /* $OpenBSD: ciss.c,v 1.68 2013/05/30 16:15:02 deraadt Exp $ */ 3 1.1 he 4 1.1 he /* 5 1.30 christos * Copyright (c) 2005,2006 Michael Shalayeff 6 1.1 he * All rights reserved. 7 1.1 he * 8 1.1 he * Permission to use, copy, modify, and distribute this software for any 9 1.1 he * purpose with or without fee is hereby granted, provided that the above 10 1.1 he * copyright notice and this permission notice appear in all copies. 11 1.1 he * 12 1.1 he * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 1.1 he * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 1.1 he * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 1.1 he * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 1.1 he * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN 17 1.1 he * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 18 1.1 he * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 1.1 he */ 20 1.1 he 21 1.1 he #include <sys/cdefs.h> 22 1.56 msaitoh __KERNEL_RCSID(0, "$NetBSD: ciss.c,v 1.56 2024/02/19 14:54:04 msaitoh Exp $"); 23 1.12 mhitch 24 1.12 mhitch #include "bio.h" 25 1.1 he 26 1.1 he /* #define CISS_DEBUG */ 27 1.1 he 28 1.1 he #include <sys/param.h> 29 1.1 he #include <sys/systm.h> 30 1.1 he #include <sys/buf.h> 31 1.1 he #include <sys/ioctl.h> 32 1.1 he #include <sys/device.h> 33 1.1 he #include <sys/kernel.h> 34 1.1 he #include <sys/malloc.h> 35 1.1 he #include <sys/proc.h> 36 1.1 he 37 1.9 ad #include <sys/bus.h> 38 1.1 he 39 1.1 he #include <dev/scsipi/scsi_all.h> 40 1.1 he #include <dev/scsipi/scsi_disk.h> 41 1.1 he #include <dev/scsipi/scsiconf.h> 42 1.23 mhitch #include <dev/scsipi/scsipi_all.h> 43 1.1 he 44 1.1 he #include <dev/ic/cissreg.h> 45 1.1 he #include <dev/ic/cissvar.h> 46 1.1 he 47 1.12 mhitch #if NBIO > 0 48 1.12 mhitch #include <dev/biovar.h> 49 1.12 mhitch #endif /* NBIO > 0 */ 50 1.12 mhitch 51 1.1 he #ifdef CISS_DEBUG 52 1.1 he #define CISS_DPRINTF(m,a) if (ciss_debug & (m)) printf a 53 1.1 he #define CISS_D_CMD 0x0001 54 1.1 he #define CISS_D_INTR 0x0002 55 1.1 he #define CISS_D_MISC 0x0004 56 1.1 he #define CISS_D_DMA 0x0008 57 1.1 he #define CISS_D_IOCTL 0x0010 58 1.1 he #define CISS_D_ERR 0x0020 59 1.1 he int ciss_debug = 0 60 1.1 he | CISS_D_CMD 61 1.1 he | CISS_D_INTR 62 1.1 he | CISS_D_MISC 63 1.1 he | CISS_D_DMA 64 1.1 he | CISS_D_IOCTL 65 1.1 he | CISS_D_ERR 66 1.1 he ; 67 1.1 he #else 68 1.1 he #define CISS_DPRINTF(m,a) /* m, a */ 69 1.1 he #endif 70 1.1 he 71 1.1 he static void ciss_scsi_cmd(struct scsipi_channel *chan, 72 1.1 he scsipi_adapter_req_t req, void *arg); 73 1.1 he static int ciss_scsi_ioctl(struct scsipi_channel *chan, u_long cmd, 74 1.7 christos void *addr, int flag, struct proc *p); 75 1.1 he static void cissminphys(struct buf *bp); 76 1.1 he 77 1.1 he static int ciss_sync(struct ciss_softc *sc); 78 1.1 he static void ciss_heartbeat(void *v); 79 1.1 he static void ciss_shutdown(void *v); 80 1.1 he 81 1.48 jdolecek static struct ciss_ccb *ciss_get_ccb(struct ciss_softc *); 82 1.48 jdolecek static void ciss_put_ccb(struct ciss_softc *, struct ciss_ccb *); 83 1.48 jdolecek static int ciss_cmd(struct ciss_softc *, struct ciss_ccb *, int, int); 84 1.48 jdolecek static int ciss_done(struct ciss_softc *, struct ciss_ccb *); 85 1.48 jdolecek static int ciss_error(struct ciss_softc *, struct ciss_ccb *); 86 1.12 mhitch struct ciss_ld *ciss_pdscan(struct ciss_softc *sc, int ld); 87 1.1 he static int ciss_inq(struct ciss_softc *sc, struct ciss_inquiry *inq); 88 1.12 mhitch int ciss_ldid(struct ciss_softc *, int, struct ciss_ldid *); 89 1.12 mhitch int ciss_ldstat(struct ciss_softc *, int, struct ciss_ldstat *); 90 1.1 he static int ciss_ldmap(struct ciss_softc *sc); 91 1.12 mhitch int ciss_pdid(struct ciss_softc *, u_int8_t, struct ciss_pdid *, int); 92 1.12 mhitch 93 1.12 mhitch #if NBIO > 0 94 1.19 cegger int ciss_ioctl(device_t, u_long, void *); 95 1.12 mhitch int ciss_ioctl_vol(struct ciss_softc *, struct bioc_vol *); 96 1.12 mhitch int ciss_blink(struct ciss_softc *, int, int, int, struct ciss_blink *); 97 1.12 mhitch int ciss_create_sensors(struct ciss_softc *); 98 1.12 mhitch void ciss_sensor_refresh(struct sysmon_envsys *, envsys_data_t *); 99 1.12 mhitch #endif /* NBIO > 0 */ 100 1.1 he 101 1.1 he static struct ciss_ccb * 102 1.1 he ciss_get_ccb(struct ciss_softc *sc) 103 1.1 he { 104 1.1 he struct ciss_ccb *ccb; 105 1.1 he 106 1.12 mhitch mutex_enter(&sc->sc_mutex); 107 1.50 jdolecek if ((ccb = TAILQ_LAST(&sc->sc_free_ccb, ciss_queue_head))) { 108 1.50 jdolecek TAILQ_REMOVE(&sc->sc_free_ccb, ccb, ccb_link); 109 1.1 he ccb->ccb_state = CISS_CCB_READY; 110 1.1 he } 111 1.12 mhitch mutex_exit(&sc->sc_mutex); 112 1.1 he return ccb; 113 1.1 he } 114 1.1 he 115 1.1 he static void 116 1.48 jdolecek ciss_put_ccb(struct ciss_softc *sc, struct ciss_ccb *ccb) 117 1.1 he { 118 1.1 he ccb->ccb_state = CISS_CCB_FREE; 119 1.12 mhitch mutex_enter(&sc->sc_mutex); 120 1.50 jdolecek TAILQ_INSERT_TAIL(&sc->sc_free_ccb, ccb, ccb_link); 121 1.12 mhitch mutex_exit(&sc->sc_mutex); 122 1.1 he } 123 1.1 he 124 1.44 jdolecek static int 125 1.44 jdolecek ciss_init_perf(struct ciss_softc *sc) 126 1.44 jdolecek { 127 1.44 jdolecek struct ciss_perf_config *pc = &sc->perfcfg; 128 1.44 jdolecek int error, total, rseg; 129 1.44 jdolecek 130 1.44 jdolecek if (sc->cfg.max_perfomant_mode_cmds) 131 1.44 jdolecek sc->maxcmd = sc->cfg.max_perfomant_mode_cmds; 132 1.44 jdolecek 133 1.44 jdolecek bus_space_read_region_4(sc->sc_iot, sc->cfg_ioh, 134 1.44 jdolecek sc->cfgoff + sc->cfg.troff, 135 1.44 jdolecek (u_int32_t *)pc, sizeof(*pc) / 4); 136 1.44 jdolecek 137 1.44 jdolecek total = sizeof(uint64_t) * sc->maxcmd; 138 1.44 jdolecek 139 1.44 jdolecek if ((error = bus_dmamem_alloc(sc->sc_dmat, total, PAGE_SIZE, 0, 140 1.44 jdolecek sc->replyseg, 1, &rseg, BUS_DMA_WAITOK))) { 141 1.44 jdolecek aprint_error(": cannot allocate perf area (%d)\n", error); 142 1.44 jdolecek return -1; 143 1.44 jdolecek } 144 1.44 jdolecek 145 1.44 jdolecek if ((error = bus_dmamem_map(sc->sc_dmat, sc->replyseg, rseg, total, 146 1.44 jdolecek (void **)&sc->perf_reply, BUS_DMA_WAITOK))) { 147 1.44 jdolecek aprint_error(": cannot map perf area (%d)\n", error); 148 1.44 jdolecek bus_dmamem_free(sc->sc_dmat, sc->replyseg, 1); 149 1.44 jdolecek return -1; 150 1.44 jdolecek } 151 1.44 jdolecek 152 1.44 jdolecek if ((error = bus_dmamap_create(sc->sc_dmat, total, 1, 153 1.44 jdolecek total, 0, BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, &sc->replymap))) { 154 1.44 jdolecek aprint_error(": cannot create perf dmamap (%d)\n", error); 155 1.44 jdolecek bus_dmamem_unmap(sc->sc_dmat, sc->perf_reply, total); 156 1.44 jdolecek sc->perf_reply = NULL; 157 1.44 jdolecek bus_dmamem_free(sc->sc_dmat, sc->replyseg, 1); 158 1.44 jdolecek return -1; 159 1.44 jdolecek } 160 1.44 jdolecek 161 1.44 jdolecek if ((error = bus_dmamap_load(sc->sc_dmat, sc->replymap, sc->perf_reply, 162 1.44 jdolecek total, NULL, BUS_DMA_WAITOK))) { 163 1.44 jdolecek aprint_error(": cannot load perf dmamap (%d)\n", error); 164 1.44 jdolecek bus_dmamap_destroy(sc->sc_dmat, sc->replymap); 165 1.44 jdolecek bus_dmamem_unmap(sc->sc_dmat, sc->perf_reply, total); 166 1.44 jdolecek sc->perf_reply = NULL; 167 1.44 jdolecek bus_dmamem_free(sc->sc_dmat, sc->replyseg, 1); 168 1.44 jdolecek return -1; 169 1.44 jdolecek } 170 1.44 jdolecek 171 1.44 jdolecek memset(sc->perf_reply, 0, total); 172 1.44 jdolecek 173 1.44 jdolecek sc->perf_cycle = 0x1; 174 1.44 jdolecek sc->perf_rqidx = 0; 175 1.44 jdolecek 176 1.44 jdolecek /* 177 1.44 jdolecek * Preload the fetch table with common command sizes. This allows the 178 1.44 jdolecek * hardware to not waste bus cycles for typical i/o commands, but also 179 1.44 jdolecek * not tax the driver to be too exact in choosing sizes. The table 180 1.44 jdolecek * is optimized for page-aligned i/o's, but since most i/o comes 181 1.44 jdolecek * from the various pagers, it's a reasonable assumption to make. 182 1.44 jdolecek */ 183 1.44 jdolecek #define CISS_FETCH_COUNT(x) \ 184 1.44 jdolecek (sizeof(struct ciss_cmd) + sizeof(struct ciss_sg_entry) * (x - 1) + 15) / 16 185 1.44 jdolecek 186 1.44 jdolecek pc->fetch_count[CISS_SG_FETCH_NONE] = CISS_FETCH_COUNT(0); 187 1.44 jdolecek pc->fetch_count[CISS_SG_FETCH_1] = CISS_FETCH_COUNT(1); 188 1.44 jdolecek pc->fetch_count[CISS_SG_FETCH_2] = CISS_FETCH_COUNT(2); 189 1.44 jdolecek pc->fetch_count[CISS_SG_FETCH_4] = CISS_FETCH_COUNT(4); 190 1.44 jdolecek pc->fetch_count[CISS_SG_FETCH_8] = CISS_FETCH_COUNT(8); 191 1.44 jdolecek pc->fetch_count[CISS_SG_FETCH_16] = CISS_FETCH_COUNT(16); 192 1.44 jdolecek pc->fetch_count[CISS_SG_FETCH_32] = CISS_FETCH_COUNT(32); 193 1.44 jdolecek pc->fetch_count[CISS_SG_FETCH_MAX] = (sc->ccblen + 15) / 16; 194 1.44 jdolecek 195 1.44 jdolecek pc->rq_size = sc->maxcmd; 196 1.44 jdolecek pc->rq_count = 1; /* Hardcode for a single queue */ 197 1.44 jdolecek pc->rq_bank_hi = 0; 198 1.44 jdolecek pc->rq_bank_lo = 0; 199 1.44 jdolecek pc->rq[0].rq_addr_hi = 0x0; 200 1.44 jdolecek pc->rq[0].rq_addr_lo = sc->replymap->dm_segs[0].ds_addr; 201 1.44 jdolecek 202 1.44 jdolecek /* 203 1.44 jdolecek * Write back the changed configuration. Tt will be picked up 204 1.44 jdolecek * by controller together with general configuration later on. 205 1.44 jdolecek */ 206 1.44 jdolecek bus_space_write_region_4(sc->sc_iot, sc->cfg_ioh, 207 1.44 jdolecek sc->cfgoff + sc->cfg.troff, 208 1.44 jdolecek (u_int32_t *)pc, sizeof(*pc) / 4); 209 1.44 jdolecek bus_space_barrier(sc->sc_iot, sc->cfg_ioh, 210 1.44 jdolecek sc->cfgoff + sc->cfg.troff, sizeof(*pc), 211 1.44 jdolecek BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE); 212 1.44 jdolecek 213 1.44 jdolecek return 0; 214 1.44 jdolecek } 215 1.44 jdolecek 216 1.1 he int 217 1.1 he ciss_attach(struct ciss_softc *sc) 218 1.1 he { 219 1.1 he struct ciss_ccb *ccb; 220 1.1 he struct ciss_cmd *cmd; 221 1.1 he struct ciss_inquiry *inq; 222 1.1 he bus_dma_segment_t seg[1]; 223 1.1 he int error, i, total, rseg, maxfer; 224 1.1 he paddr_t pa; 225 1.1 he 226 1.1 he if (sc->cfg.signature != CISS_SIGNATURE) { 227 1.36 msaitoh aprint_error(": bad sign 0x%08x\n", sc->cfg.signature); 228 1.1 he return -1; 229 1.1 he } 230 1.1 he 231 1.44 jdolecek if (!(sc->cfg.methods & (CISS_METH_SIMPL|CISS_METH_PERF))) { 232 1.44 jdolecek aprint_error(": no supported method 0x%08x\n", sc->cfg.methods); 233 1.1 he return -1; 234 1.1 he } 235 1.1 he 236 1.44 jdolecek if (!sc->cfg.maxsg) 237 1.44 jdolecek sc->cfg.maxsg = MAXPHYS / PAGE_SIZE + 1; 238 1.44 jdolecek 239 1.44 jdolecek sc->maxcmd = sc->cfg.maxcmd; 240 1.44 jdolecek sc->maxsg = sc->cfg.maxsg; 241 1.44 jdolecek if (sc->maxsg > MAXPHYS / PAGE_SIZE + 1) 242 1.44 jdolecek sc->maxsg = MAXPHYS / PAGE_SIZE + 1; 243 1.44 jdolecek i = sizeof(struct ciss_ccb) + 244 1.44 jdolecek sizeof(ccb->ccb_cmd.sgl[0]) * (sc->maxsg - 1); 245 1.44 jdolecek for (sc->ccblen = 0x10; sc->ccblen < i; sc->ccblen <<= 1); 246 1.44 jdolecek 247 1.1 he sc->cfg.paddr_lim = 0; /* 32bit addrs */ 248 1.1 he sc->cfg.int_delay = 0; /* disable coalescing */ 249 1.1 he sc->cfg.int_count = 0; 250 1.1 he strlcpy(sc->cfg.hostname, "HUMPPA", sizeof(sc->cfg.hostname)); 251 1.1 he sc->cfg.driverf |= CISS_DRV_PRF; /* enable prefetch */ 252 1.44 jdolecek if (CISS_PERF_SUPPORTED(sc)) { 253 1.44 jdolecek sc->cfg.rmethod = CISS_METH_PERF | CISS_METH_SHORT_TAG; 254 1.44 jdolecek if (ciss_init_perf(sc) != 0) { 255 1.44 jdolecek /* Don't try to fallback, just bail out */ 256 1.44 jdolecek return -1; 257 1.44 jdolecek } 258 1.44 jdolecek } else { 259 1.44 jdolecek sc->cfg.rmethod = CISS_METH_SIMPL; 260 1.44 jdolecek } 261 1.1 he 262 1.1 he bus_space_write_region_4(sc->sc_iot, sc->cfg_ioh, sc->cfgoff, 263 1.1 he (u_int32_t *)&sc->cfg, sizeof(sc->cfg) / 4); 264 1.1 he bus_space_barrier(sc->sc_iot, sc->cfg_ioh, sc->cfgoff, sizeof(sc->cfg), 265 1.1 he BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE); 266 1.1 he 267 1.1 he bus_space_write_4(sc->sc_iot, sc->sc_ioh, CISS_IDB, CISS_IDB_CFG); 268 1.1 he bus_space_barrier(sc->sc_iot, sc->sc_ioh, CISS_IDB, 4, 269 1.1 he BUS_SPACE_BARRIER_WRITE); 270 1.1 he for (i = 1000; i--; DELAY(1000)) { 271 1.1 he /* XXX maybe IDB is really 64bit? - hp dl380 needs this */ 272 1.1 he (void)bus_space_read_4(sc->sc_iot, sc->sc_ioh, CISS_IDB + 4); 273 1.1 he if (!(bus_space_read_4(sc->sc_iot, sc->sc_ioh, CISS_IDB) & CISS_IDB_CFG)) 274 1.1 he break; 275 1.1 he bus_space_barrier(sc->sc_iot, sc->sc_ioh, CISS_IDB, 4, 276 1.1 he BUS_SPACE_BARRIER_READ); 277 1.1 he } 278 1.1 he 279 1.1 he if (bus_space_read_4(sc->sc_iot, sc->sc_ioh, CISS_IDB) & CISS_IDB_CFG) { 280 1.44 jdolecek aprint_error(": cannot set config\n"); 281 1.1 he return -1; 282 1.1 he } 283 1.1 he 284 1.1 he bus_space_read_region_4(sc->sc_iot, sc->cfg_ioh, sc->cfgoff, 285 1.1 he (u_int32_t *)&sc->cfg, sizeof(sc->cfg) / 4); 286 1.1 he 287 1.44 jdolecek if (!(sc->cfg.amethod & (CISS_METH_SIMPL|CISS_METH_PERF))) { 288 1.44 jdolecek aprint_error(": cannot set method 0x%08x\n", sc->cfg.amethod); 289 1.1 he return -1; 290 1.1 he } 291 1.1 he 292 1.1 he /* i'm ready for you and i hope you're ready for me */ 293 1.1 he for (i = 30000; i--; DELAY(1000)) { 294 1.1 he if (bus_space_read_4(sc->sc_iot, sc->cfg_ioh, sc->cfgoff + 295 1.1 he offsetof(struct ciss_config, amethod)) & CISS_METH_READY) 296 1.1 he break; 297 1.1 he bus_space_barrier(sc->sc_iot, sc->cfg_ioh, sc->cfgoff + 298 1.1 he offsetof(struct ciss_config, amethod), 4, 299 1.1 he BUS_SPACE_BARRIER_READ); 300 1.1 he } 301 1.1 he 302 1.1 he if (!(bus_space_read_4(sc->sc_iot, sc->cfg_ioh, sc->cfgoff + 303 1.1 he offsetof(struct ciss_config, amethod)) & CISS_METH_READY)) { 304 1.36 msaitoh aprint_error(": she never came ready for me 0x%08x\n", 305 1.1 he sc->cfg.amethod); 306 1.1 he return -1; 307 1.1 he } 308 1.1 he 309 1.12 mhitch mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_VM); 310 1.12 mhitch mutex_init(&sc->sc_mutex_scratch, MUTEX_DEFAULT, IPL_VM); 311 1.12 mhitch cv_init(&sc->sc_condvar, "ciss_cmd"); 312 1.1 he 313 1.1 he total = sc->ccblen * sc->maxcmd; 314 1.1 he if ((error = bus_dmamem_alloc(sc->sc_dmat, total, PAGE_SIZE, 0, 315 1.1 he sc->cmdseg, 1, &rseg, BUS_DMA_NOWAIT))) { 316 1.36 msaitoh aprint_error(": cannot allocate CCBs (%d)\n", error); 317 1.1 he return -1; 318 1.1 he } 319 1.1 he 320 1.1 he if ((error = bus_dmamem_map(sc->sc_dmat, sc->cmdseg, rseg, total, 321 1.7 christos (void **)&sc->ccbs, BUS_DMA_NOWAIT))) { 322 1.36 msaitoh aprint_error(": cannot map CCBs (%d)\n", error); 323 1.1 he return -1; 324 1.1 he } 325 1.16 cegger memset(sc->ccbs, 0, total); 326 1.1 he 327 1.1 he if ((error = bus_dmamap_create(sc->sc_dmat, total, 1, 328 1.1 he total, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &sc->cmdmap))) { 329 1.36 msaitoh aprint_error(": cannot create CCBs dmamap (%d)\n", error); 330 1.1 he bus_dmamem_free(sc->sc_dmat, sc->cmdseg, 1); 331 1.1 he return -1; 332 1.1 he } 333 1.1 he 334 1.1 he if ((error = bus_dmamap_load(sc->sc_dmat, sc->cmdmap, sc->ccbs, total, 335 1.1 he NULL, BUS_DMA_NOWAIT))) { 336 1.36 msaitoh aprint_error(": cannot load CCBs dmamap (%d)\n", error); 337 1.54 rin bus_dmamap_destroy(sc->sc_dmat, sc->cmdmap); 338 1.1 he bus_dmamem_free(sc->sc_dmat, sc->cmdseg, 1); 339 1.1 he return -1; 340 1.1 he } 341 1.1 he 342 1.50 jdolecek TAILQ_INIT(&sc->sc_free_ccb); 343 1.1 he 344 1.1 he maxfer = sc->maxsg * PAGE_SIZE; 345 1.1 he for (i = 0; total > 0 && i < sc->maxcmd; i++, total -= sc->ccblen) { 346 1.7 christos ccb = (struct ciss_ccb *) ((char *)sc->ccbs + i * sc->ccblen); 347 1.1 he cmd = &ccb->ccb_cmd; 348 1.1 he pa = sc->cmdseg[0].ds_addr + i * sc->ccblen; 349 1.1 he 350 1.1 he ccb->ccb_cmdpa = pa + offsetof(struct ciss_ccb, ccb_cmd); 351 1.1 he ccb->ccb_state = CISS_CCB_FREE; 352 1.1 he 353 1.1 he cmd->id = htole32(i << 2); 354 1.1 he cmd->id_hi = htole32(0); 355 1.1 he cmd->sgin = sc->maxsg; 356 1.1 he cmd->sglen = htole16((u_int16_t)cmd->sgin); 357 1.1 he cmd->err_len = htole32(sizeof(ccb->ccb_err)); 358 1.1 he pa += offsetof(struct ciss_ccb, ccb_err); 359 1.1 he cmd->err_pa = htole64((u_int64_t)pa); 360 1.1 he 361 1.1 he if ((error = bus_dmamap_create(sc->sc_dmat, maxfer, sc->maxsg, 362 1.1 he maxfer, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, 363 1.1 he &ccb->ccb_dmamap))) 364 1.1 he break; 365 1.1 he 366 1.50 jdolecek TAILQ_INSERT_TAIL(&sc->sc_free_ccb, ccb, ccb_link); 367 1.1 he } 368 1.1 he 369 1.1 he if (i < sc->maxcmd) { 370 1.36 msaitoh aprint_error(": cannot create ccb#%d dmamap (%d)\n", i, error); 371 1.1 he if (i == 0) { 372 1.1 he /* TODO leaking cmd's dmamaps and shitz */ 373 1.54 rin bus_dmamap_destroy(sc->sc_dmat, sc->cmdmap); 374 1.1 he bus_dmamem_free(sc->sc_dmat, sc->cmdseg, 1); 375 1.1 he return -1; 376 1.1 he } 377 1.1 he } 378 1.1 he 379 1.1 he if ((error = bus_dmamem_alloc(sc->sc_dmat, PAGE_SIZE, PAGE_SIZE, 0, 380 1.1 he seg, 1, &rseg, BUS_DMA_NOWAIT))) { 381 1.36 msaitoh aprint_error(": cannot allocate scratch buffer (%d)\n", error); 382 1.1 he return -1; 383 1.1 he } 384 1.1 he 385 1.1 he if ((error = bus_dmamem_map(sc->sc_dmat, seg, rseg, PAGE_SIZE, 386 1.7 christos (void **)&sc->scratch, BUS_DMA_NOWAIT))) { 387 1.36 msaitoh aprint_error(": cannot map scratch buffer (%d)\n", error); 388 1.1 he return -1; 389 1.1 he } 390 1.16 cegger memset(sc->scratch, 0, PAGE_SIZE); 391 1.12 mhitch sc->sc_waitflag = XS_CTL_NOSLEEP; /* can't sleep yet */ 392 1.1 he 393 1.36 msaitoh mutex_enter(&sc->sc_mutex_scratch); /* is this really needed? */ 394 1.1 he inq = sc->scratch; 395 1.1 he if (ciss_inq(sc, inq)) { 396 1.36 msaitoh aprint_error(": adapter inquiry failed\n"); 397 1.12 mhitch mutex_exit(&sc->sc_mutex_scratch); 398 1.54 rin bus_dmamap_destroy(sc->sc_dmat, sc->cmdmap); 399 1.1 he bus_dmamem_free(sc->sc_dmat, sc->cmdseg, 1); 400 1.1 he return -1; 401 1.1 he } 402 1.1 he 403 1.1 he if (!(inq->flags & CISS_INQ_BIGMAP)) { 404 1.36 msaitoh aprint_error(": big map is not supported, flags=0x%x\n", 405 1.1 he inq->flags); 406 1.12 mhitch mutex_exit(&sc->sc_mutex_scratch); 407 1.54 rin bus_dmamap_destroy(sc->sc_dmat, sc->cmdmap); 408 1.1 he bus_dmamem_free(sc->sc_dmat, sc->cmdseg, 1); 409 1.1 he return -1; 410 1.1 he } 411 1.1 he 412 1.1 he sc->maxunits = inq->numld; 413 1.1 he sc->nbus = inq->nscsi_bus; 414 1.14 he sc->ndrives = inq->buswidth ? inq->buswidth : 256; 415 1.36 msaitoh aprint_normal(": %d LD%s, HW rev %d, FW %4.4s/%4.4s", 416 1.1 he inq->numld, inq->numld == 1? "" : "s", 417 1.1 he inq->hw_rev, inq->fw_running, inq->fw_stored); 418 1.1 he 419 1.30 christos if (sc->cfg.methods & CISS_METH_FIFO64) 420 1.36 msaitoh aprint_normal(", 64bit fifo"); 421 1.30 christos else if (sc->cfg.methods & CISS_METH_FIFO64_RRO) 422 1.36 msaitoh aprint_normal(", 64bit fifo rro"); 423 1.44 jdolecek aprint_normal(", method %s %#x", 424 1.44 jdolecek CISS_IS_PERF(sc) ? "perf" : "simple", 425 1.44 jdolecek sc->cfg.amethod); 426 1.36 msaitoh aprint_normal("\n"); 427 1.30 christos 428 1.12 mhitch mutex_exit(&sc->sc_mutex_scratch); 429 1.1 he 430 1.56 msaitoh if (sc->maxunits == 0) { 431 1.56 msaitoh bus_dmamem_free(sc->sc_dmat, sc->cmdseg, 1); 432 1.56 msaitoh bus_dmamap_destroy(sc->sc_dmat, sc->cmdmap); 433 1.56 msaitoh aprint_error_dev(sc->sc_dev, 434 1.56 msaitoh "No any LD. This driver can't attach.\n"); 435 1.56 msaitoh return -1; 436 1.56 msaitoh } 437 1.56 msaitoh 438 1.8 ad callout_init(&sc->sc_hb, 0); 439 1.1 he callout_setfunc(&sc->sc_hb, ciss_heartbeat, sc); 440 1.1 he callout_schedule(&sc->sc_hb, hz * 3); 441 1.1 he 442 1.1 he /* map LDs */ 443 1.1 he if (ciss_ldmap(sc)) { 444 1.29 chs aprint_error_dev(sc->sc_dev, "adapter LD map failed\n"); 445 1.54 rin bus_dmamap_destroy(sc->sc_dmat, sc->cmdmap); 446 1.1 he bus_dmamem_free(sc->sc_dmat, sc->cmdseg, 1); 447 1.1 he return -1; 448 1.1 he } 449 1.1 he 450 1.41 chs sc->sc_lds = malloc(sc->maxunits * sizeof(*sc->sc_lds), 451 1.41 chs M_DEVBUF, M_WAITOK | M_ZERO); 452 1.1 he 453 1.12 mhitch sc->sc_flush = CISS_FLUSH_ENABLE; 454 1.12 mhitch if (!(sc->sc_sh = shutdownhook_establish(ciss_shutdown, sc))) { 455 1.36 msaitoh aprint_error_dev(sc->sc_dev, 456 1.36 msaitoh "unable to establish shutdown hook\n"); 457 1.54 rin bus_dmamap_destroy(sc->sc_dmat, sc->cmdmap); 458 1.1 he bus_dmamem_free(sc->sc_dmat, sc->cmdseg, 1); 459 1.1 he return -1; 460 1.1 he } 461 1.1 he 462 1.1 he sc->sc_channel.chan_adapter = &sc->sc_adapter; 463 1.1 he sc->sc_channel.chan_bustype = &scsi_bustype; 464 1.1 he sc->sc_channel.chan_channel = 0; 465 1.1 he sc->sc_channel.chan_ntargets = sc->maxunits; 466 1.13 mhitch sc->sc_channel.chan_nluns = 1; /* ciss doesn't really have SCSI luns */ 467 1.23 mhitch sc->sc_channel.chan_openings = sc->maxcmd; 468 1.12 mhitch #if NBIO > 0 469 1.12 mhitch /* XXX Reserve some ccb's for sensor and bioctl. */ 470 1.12 mhitch if (sc->sc_channel.chan_openings > 2) 471 1.12 mhitch sc->sc_channel.chan_openings -= 2; 472 1.12 mhitch #endif 473 1.1 he sc->sc_channel.chan_flags = 0; 474 1.1 he sc->sc_channel.chan_id = sc->maxunits; 475 1.1 he 476 1.29 chs sc->sc_adapter.adapt_dev = sc->sc_dev; 477 1.12 mhitch sc->sc_adapter.adapt_openings = sc->sc_channel.chan_openings; 478 1.39 riastrad sc->sc_adapter.adapt_max_periph = uimin(sc->sc_adapter.adapt_openings, 256); 479 1.1 he sc->sc_adapter.adapt_request = ciss_scsi_cmd; 480 1.1 he sc->sc_adapter.adapt_minphys = cissminphys; 481 1.1 he sc->sc_adapter.adapt_ioctl = ciss_scsi_ioctl; 482 1.1 he sc->sc_adapter.adapt_nchannels = 1; 483 1.52 thorpej config_found(sc->sc_dev, &sc->sc_channel, scsiprint, CFARGS_NONE); 484 1.1 he 485 1.1 he #if 0 486 1.1 he sc->sc_link_raw.adapter_softc = sc; 487 1.12 mhitch sc->sc_link.openings = sc->sc_channel.chan_openings; 488 1.1 he sc->sc_link_raw.adapter = &ciss_raw_switch; 489 1.1 he sc->sc_link_raw.adapter_target = sc->ndrives; 490 1.1 he sc->sc_link_raw.adapter_buswidth = sc->ndrives; 491 1.52 thorpej config_found(sc->sc_dev, &sc->sc_channel, scsiprint, CFARGS_NONE); 492 1.1 he #endif 493 1.1 he 494 1.12 mhitch #if NBIO > 0 495 1.12 mhitch /* now map all the physdevs into their lds */ 496 1.12 mhitch /* XXX currently we assign all of them into ld0 */ 497 1.12 mhitch for (i = 0; i < sc->maxunits && i < 1; i++) 498 1.12 mhitch if (!(sc->sc_lds[i] = ciss_pdscan(sc, i))) { 499 1.12 mhitch sc->sc_waitflag = 0; /* we can sleep now */ 500 1.12 mhitch return 0; 501 1.12 mhitch } 502 1.12 mhitch 503 1.29 chs if (bio_register(sc->sc_dev, ciss_ioctl) != 0) 504 1.29 chs aprint_error_dev(sc->sc_dev, "controller registration failed"); 505 1.12 mhitch else 506 1.12 mhitch sc->sc_ioctl = ciss_ioctl; 507 1.12 mhitch if (ciss_create_sensors(sc) != 0) 508 1.29 chs aprint_error_dev(sc->sc_dev, "unable to create sensors"); 509 1.1 he #endif 510 1.12 mhitch sc->sc_waitflag = 0; /* we can sleep now */ 511 1.1 he 512 1.1 he return 0; 513 1.1 he } 514 1.1 he 515 1.1 he static void 516 1.1 he ciss_shutdown(void *v) 517 1.1 he { 518 1.1 he struct ciss_softc *sc = v; 519 1.1 he 520 1.1 he sc->sc_flush = CISS_FLUSH_DISABLE; 521 1.1 he /* timeout_del(&sc->sc_hb); */ 522 1.1 he ciss_sync(sc); 523 1.1 he } 524 1.1 he 525 1.1 he static void 526 1.1 he cissminphys(struct buf *bp) 527 1.1 he { 528 1.30 christos #if 0 /* TODO */ 529 1.1 he #define CISS_MAXFER (PAGE_SIZE * (sc->maxsg + 1)) 530 1.1 he if (bp->b_bcount > CISS_MAXFER) 531 1.1 he bp->b_bcount = CISS_MAXFER; 532 1.1 he #endif 533 1.1 he minphys(bp); 534 1.2 martti } 535 1.1 he 536 1.44 jdolecek static void 537 1.44 jdolecek ciss_enqueue(struct ciss_softc *sc, ciss_queue_head *q, uint32_t id) 538 1.34 christos { 539 1.34 christos struct ciss_ccb *ccb; 540 1.44 jdolecek 541 1.44 jdolecek KASSERT(mutex_owned(&sc->sc_mutex)); 542 1.44 jdolecek 543 1.44 jdolecek KASSERT((id >> 2) <= sc->maxcmd); 544 1.44 jdolecek ccb = (struct ciss_ccb *) ((char *)sc->ccbs + (id >> 2) * sc->ccblen); 545 1.44 jdolecek ccb->ccb_cmd.id = htole32(id); 546 1.44 jdolecek ccb->ccb_cmd.id_hi = htole32(0); 547 1.50 jdolecek TAILQ_INSERT_TAIL(q, ccb, ccb_link); 548 1.44 jdolecek } 549 1.44 jdolecek 550 1.44 jdolecek static void 551 1.44 jdolecek ciss_completed_simple(struct ciss_softc *sc, ciss_queue_head *q) 552 1.44 jdolecek { 553 1.34 christos uint32_t id; 554 1.34 christos 555 1.44 jdolecek KASSERT(mutex_owned(&sc->sc_mutex)); 556 1.44 jdolecek 557 1.44 jdolecek for (;;) { 558 1.44 jdolecek if (sc->cfg.methods & CISS_METH_FIFO64) { 559 1.44 jdolecek if (bus_space_read_4(sc->sc_iot, sc->sc_ioh, 560 1.44 jdolecek CISS_OUTQ64_HI) == 0xffffffff) { 561 1.44 jdolecek CISS_DPRINTF(CISS_D_CMD, ("Q")); 562 1.44 jdolecek break; 563 1.44 jdolecek } 564 1.44 jdolecek id = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 565 1.44 jdolecek CISS_OUTQ64_LO); 566 1.44 jdolecek } else if (sc->cfg.methods & CISS_METH_FIFO64_RRO) { 567 1.44 jdolecek id = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 568 1.44 jdolecek CISS_OUTQ64_LO); 569 1.44 jdolecek if (id == 0xffffffff) { 570 1.44 jdolecek CISS_DPRINTF(CISS_D_CMD, ("Q")); 571 1.44 jdolecek break; 572 1.44 jdolecek } 573 1.44 jdolecek (void)bus_space_read_4(sc->sc_iot, sc->sc_ioh, 574 1.44 jdolecek CISS_OUTQ64_HI); 575 1.44 jdolecek } else { 576 1.44 jdolecek id = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 577 1.44 jdolecek CISS_OUTQ); 578 1.44 jdolecek if (id == 0xffffffff) { 579 1.44 jdolecek CISS_DPRINTF(CISS_D_CMD, ("Q")); 580 1.44 jdolecek break; 581 1.44 jdolecek } 582 1.44 jdolecek } 583 1.44 jdolecek 584 1.44 jdolecek CISS_DPRINTF(CISS_D_CMD, ("got=0x%x ", id)); 585 1.44 jdolecek ciss_enqueue(sc, q, id); 586 1.34 christos } 587 1.44 jdolecek } 588 1.44 jdolecek 589 1.44 jdolecek static void 590 1.44 jdolecek ciss_completed_perf(struct ciss_softc *sc, ciss_queue_head *q) 591 1.44 jdolecek { 592 1.44 jdolecek uint32_t id; 593 1.44 jdolecek 594 1.44 jdolecek KASSERT(mutex_owned(&sc->sc_mutex)); 595 1.34 christos 596 1.44 jdolecek for (;;) { 597 1.44 jdolecek id = sc->perf_reply[sc->perf_rqidx]; 598 1.44 jdolecek if ((id & CISS_CYCLE_MASK) != sc->perf_cycle) 599 1.44 jdolecek break; 600 1.44 jdolecek 601 1.44 jdolecek if (++sc->perf_rqidx == sc->maxcmd) { 602 1.44 jdolecek sc->perf_rqidx = 0; 603 1.44 jdolecek sc->perf_cycle ^= 1; 604 1.34 christos } 605 1.44 jdolecek 606 1.44 jdolecek CISS_DPRINTF(CISS_D_CMD, ("got=0x%x ", id)); 607 1.44 jdolecek ciss_enqueue(sc, q, id); 608 1.34 christos } 609 1.34 christos } 610 1.34 christos 611 1.34 christos static int 612 1.34 christos ciss_poll(struct ciss_softc *sc, struct ciss_ccb *ccb, int ms) 613 1.34 christos { 614 1.44 jdolecek ciss_queue_head q; 615 1.34 christos struct ciss_ccb *ccb1; 616 1.34 christos 617 1.50 jdolecek TAILQ_INIT(&q); 618 1.34 christos ms /= 10; 619 1.34 christos 620 1.34 christos while (ms-- > 0) { 621 1.34 christos DELAY(10); 622 1.44 jdolecek mutex_enter(&sc->sc_mutex); 623 1.44 jdolecek if (CISS_IS_PERF(sc)) 624 1.44 jdolecek ciss_completed_perf(sc, &q); 625 1.44 jdolecek else 626 1.44 jdolecek ciss_completed_simple(sc, &q); 627 1.44 jdolecek mutex_exit(&sc->sc_mutex); 628 1.44 jdolecek 629 1.50 jdolecek while (!TAILQ_EMPTY(&q)) { 630 1.50 jdolecek ccb1 = TAILQ_FIRST(&q); 631 1.50 jdolecek TAILQ_REMOVE(&q, ccb1, ccb_link); 632 1.44 jdolecek 633 1.44 jdolecek KASSERT(ccb1->ccb_state == CISS_CCB_ONQ); 634 1.48 jdolecek ciss_done(sc, ccb1); 635 1.44 jdolecek if (ccb1 == ccb) { 636 1.50 jdolecek KASSERT(TAILQ_EMPTY(&q)); 637 1.44 jdolecek return 0; 638 1.44 jdolecek } 639 1.44 jdolecek } 640 1.34 christos } 641 1.34 christos 642 1.34 christos return ETIMEDOUT; 643 1.34 christos } 644 1.34 christos 645 1.34 christos static int 646 1.34 christos ciss_wait(struct ciss_softc *sc, struct ciss_ccb *ccb, int ms) 647 1.34 christos { 648 1.34 christos int tohz, etick; 649 1.34 christos 650 1.34 christos tohz = mstohz(ms); 651 1.34 christos if (tohz == 0) 652 1.34 christos tohz = 1; 653 1.42 maxv etick = getticks() + tohz; 654 1.34 christos 655 1.34 christos for (;;) { 656 1.34 christos CISS_DPRINTF(CISS_D_CMD, ("cv_timedwait(%d) ", tohz)); 657 1.34 christos mutex_enter(&sc->sc_mutex); 658 1.34 christos if (cv_timedwait(&sc->sc_condvar, &sc->sc_mutex, tohz) 659 1.34 christos == EWOULDBLOCK) { 660 1.34 christos mutex_exit(&sc->sc_mutex); 661 1.34 christos return EWOULDBLOCK; 662 1.34 christos } 663 1.34 christos mutex_exit(&sc->sc_mutex); 664 1.34 christos if (ccb->ccb_state == CISS_CCB_ONQ) { 665 1.48 jdolecek ciss_done(sc, ccb); 666 1.34 christos return 0; 667 1.34 christos } 668 1.42 maxv tohz = etick - getticks(); 669 1.34 christos if (tohz <= 0) 670 1.34 christos return EWOULDBLOCK; 671 1.34 christos CISS_DPRINTF(CISS_D_CMD, ("T")); 672 1.34 christos } 673 1.34 christos } 674 1.34 christos 675 1.1 he /* 676 1.55 andvar * submit a command and optionally wait for completion. 677 1.1 he * wait arg abuses XS_CTL_POLL|XS_CTL_NOSLEEP flags to request 678 1.1 he * to wait (XS_CTL_POLL) and to allow tsleep() (!XS_CTL_NOSLEEP) 679 1.1 he * instead of busy loop waiting 680 1.1 he */ 681 1.1 he static int 682 1.48 jdolecek ciss_cmd(struct ciss_softc *sc, struct ciss_ccb *ccb, int flags, int wait) 683 1.1 he { 684 1.1 he struct ciss_cmd *cmd = &ccb->ccb_cmd; 685 1.1 he bus_dmamap_t dmap = ccb->ccb_dmamap; 686 1.30 christos u_int64_t addr; 687 1.34 christos int i, error = 0; 688 1.44 jdolecek const bool pollsleep = ((wait & (XS_CTL_POLL|XS_CTL_NOSLEEP)) == 689 1.44 jdolecek XS_CTL_POLL); 690 1.1 he 691 1.1 he if (ccb->ccb_state != CISS_CCB_READY) { 692 1.29 chs printf("%s: ccb %d not ready state=0x%x\n", device_xname(sc->sc_dev), 693 1.1 he cmd->id, ccb->ccb_state); 694 1.1 he return (EINVAL); 695 1.1 he } 696 1.1 he 697 1.1 he if (ccb->ccb_data) { 698 1.1 he bus_dma_segment_t *sgd; 699 1.1 he 700 1.1 he if ((error = bus_dmamap_load(sc->sc_dmat, dmap, ccb->ccb_data, 701 1.1 he ccb->ccb_len, NULL, flags))) { 702 1.1 he if (error == EFBIG) 703 1.1 he printf("more than %d dma segs\n", sc->maxsg); 704 1.1 he else 705 1.1 he printf("error %d loading dma map\n", error); 706 1.48 jdolecek ciss_put_ccb(sc, ccb); 707 1.1 he return (error); 708 1.1 he } 709 1.1 he cmd->sgin = dmap->dm_nsegs; 710 1.1 he 711 1.1 he sgd = dmap->dm_segs; 712 1.22 jakllsch CISS_DPRINTF(CISS_D_DMA, ("data=%p/%zu<%#" PRIxPADDR "/%zu", 713 1.22 jakllsch ccb->ccb_data, ccb->ccb_len, sgd->ds_addr, sgd->ds_len)); 714 1.1 he 715 1.1 he for (i = 0; i < dmap->dm_nsegs; sgd++, i++) { 716 1.1 he cmd->sgl[i].addr_lo = htole32(sgd->ds_addr); 717 1.1 he cmd->sgl[i].addr_hi = 718 1.1 he htole32((u_int64_t)sgd->ds_addr >> 32); 719 1.1 he cmd->sgl[i].len = htole32(sgd->ds_len); 720 1.1 he cmd->sgl[i].flags = htole32(0); 721 1.4 christos if (i) { 722 1.1 he CISS_DPRINTF(CISS_D_DMA, 723 1.21 jym (",%#" PRIxPADDR "/%zu", sgd->ds_addr, 724 1.21 jym sgd->ds_len)); 725 1.4 christos } 726 1.1 he } 727 1.1 he 728 1.1 he CISS_DPRINTF(CISS_D_DMA, ("> ")); 729 1.1 he 730 1.1 he bus_dmamap_sync(sc->sc_dmat, dmap, 0, dmap->dm_mapsize, 731 1.1 he BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 732 1.44 jdolecek 733 1.44 jdolecek if (dmap->dm_nsegs == 0) 734 1.44 jdolecek ccb->ccb_sg_tag = CISS_SG_FETCH_NONE; 735 1.44 jdolecek else if (dmap->dm_nsegs == 1) 736 1.44 jdolecek ccb->ccb_sg_tag = CISS_SG_FETCH_1; 737 1.44 jdolecek else if (dmap->dm_nsegs == 2) 738 1.44 jdolecek ccb->ccb_sg_tag = CISS_SG_FETCH_2; 739 1.44 jdolecek else if (dmap->dm_nsegs <= 4) 740 1.44 jdolecek ccb->ccb_sg_tag = CISS_SG_FETCH_4; 741 1.44 jdolecek else if (dmap->dm_nsegs <= 8) 742 1.44 jdolecek ccb->ccb_sg_tag = CISS_SG_FETCH_8; 743 1.44 jdolecek else if (dmap->dm_nsegs <= 16) 744 1.44 jdolecek ccb->ccb_sg_tag = CISS_SG_FETCH_16; 745 1.44 jdolecek else if (dmap->dm_nsegs <= 32) 746 1.44 jdolecek ccb->ccb_sg_tag = CISS_SG_FETCH_32; 747 1.44 jdolecek else 748 1.44 jdolecek ccb->ccb_sg_tag = CISS_SG_FETCH_MAX; 749 1.44 jdolecek } else { 750 1.44 jdolecek ccb->ccb_sg_tag = CISS_SG_FETCH_NONE; 751 1.1 he cmd->sgin = 0; 752 1.44 jdolecek } 753 1.1 he cmd->sglen = htole16((u_int16_t)cmd->sgin); 754 1.16 cegger memset(&ccb->ccb_err, 0, sizeof(ccb->ccb_err)); 755 1.1 he 756 1.1 he bus_dmamap_sync(sc->sc_dmat, sc->cmdmap, 0, sc->cmdmap->dm_mapsize, 757 1.1 he BUS_DMASYNC_PREWRITE); 758 1.1 he 759 1.1 he if ((wait & (XS_CTL_POLL|XS_CTL_NOSLEEP)) == (XS_CTL_POLL|XS_CTL_NOSLEEP)) 760 1.1 he bus_space_write_4(sc->sc_iot, sc->sc_ioh, CISS_IMR, 761 1.1 he bus_space_read_4(sc->sc_iot, sc->sc_ioh, CISS_IMR) | sc->iem); 762 1.1 he 763 1.44 jdolecek if (!pollsleep) 764 1.44 jdolecek ccb->ccb_state = CISS_CCB_ONQ; 765 1.44 jdolecek else 766 1.44 jdolecek ccb->ccb_state = CISS_CCB_POLL; 767 1.1 he CISS_DPRINTF(CISS_D_CMD, ("submit=0x%x ", cmd->id)); 768 1.44 jdolecek 769 1.44 jdolecek addr = (u_int64_t)ccb->ccb_cmdpa; 770 1.44 jdolecek if (CISS_IS_PERF(sc)) { 771 1.44 jdolecek KASSERT((addr & 0xf) == 0); 772 1.44 jdolecek /* 773 1.44 jdolecek * The bits in addr in performant mean: 774 1.44 jdolecek * - performant mode bit (bit 0) 775 1.44 jdolecek * - pull count (bits 1-3) 776 1.44 jdolecek * There is no support for ioaccel mode 777 1.44 jdolecek */ 778 1.44 jdolecek addr |= 1 | (ccb->ccb_sg_tag << 1); 779 1.44 jdolecek } 780 1.30 christos if (sc->cfg.methods & (CISS_METH_FIFO64|CISS_METH_FIFO64_RRO)) { 781 1.30 christos /* 782 1.30 christos * Write the upper 32bits immediately before the lower 783 1.30 christos * 32bits and set bit 63 to indicate 64bit FIFO mode. 784 1.30 christos */ 785 1.30 christos bus_space_write_4(sc->sc_iot, sc->sc_ioh, CISS_INQ64_HI, 786 1.30 christos (addr >> 32) | 0x80000000); 787 1.30 christos bus_space_write_4(sc->sc_iot, sc->sc_ioh, CISS_INQ64_LO, 788 1.30 christos addr & 0x00000000ffffffffULL); 789 1.30 christos } else 790 1.30 christos bus_space_write_4(sc->sc_iot, sc->sc_ioh, CISS_INQ, 791 1.44 jdolecek (uint32_t)addr); 792 1.1 he 793 1.1 he if (wait & XS_CTL_POLL) { 794 1.34 christos int ms; 795 1.1 he CISS_DPRINTF(CISS_D_CMD, ("waiting ")); 796 1.1 he 797 1.34 christos ms = ccb->ccb_xs ? ccb->ccb_xs->timeout : 60000; 798 1.44 jdolecek if (pollsleep) 799 1.44 jdolecek error = ciss_wait(sc, ccb, ms); 800 1.44 jdolecek else 801 1.34 christos error = ciss_poll(sc, ccb, ms); 802 1.1 he 803 1.1 he /* if never got a chance to be done above... */ 804 1.1 he if (ccb->ccb_state != CISS_CCB_FREE) { 805 1.34 christos KASSERT(error); 806 1.1 he ccb->ccb_err.cmd_stat = CISS_ERR_TMO; 807 1.48 jdolecek error = ciss_done(sc, ccb); 808 1.1 he } 809 1.1 he 810 1.1 he CISS_DPRINTF(CISS_D_CMD, ("done %d:%d", 811 1.1 he ccb->ccb_err.cmd_stat, ccb->ccb_err.scsi_stat)); 812 1.1 he } 813 1.1 he 814 1.1 he if ((wait & (XS_CTL_POLL|XS_CTL_NOSLEEP)) == (XS_CTL_POLL|XS_CTL_NOSLEEP)) 815 1.1 he bus_space_write_4(sc->sc_iot, sc->sc_ioh, CISS_IMR, 816 1.1 he bus_space_read_4(sc->sc_iot, sc->sc_ioh, CISS_IMR) & ~sc->iem); 817 1.1 he 818 1.1 he return (error); 819 1.1 he } 820 1.1 he 821 1.1 he static int 822 1.48 jdolecek ciss_done(struct ciss_softc *sc, struct ciss_ccb *ccb) 823 1.1 he { 824 1.1 he struct scsipi_xfer *xs = ccb->ccb_xs; 825 1.2 martti struct ciss_cmd *cmd; 826 1.1 he int error = 0; 827 1.1 he 828 1.1 he CISS_DPRINTF(CISS_D_CMD, ("ciss_done(%p) ", ccb)); 829 1.1 he 830 1.1 he if (ccb->ccb_state != CISS_CCB_ONQ) { 831 1.1 he printf("%s: unqueued ccb %p ready, state=0x%x\n", 832 1.29 chs device_xname(sc->sc_dev), ccb, ccb->ccb_state); 833 1.1 he return 1; 834 1.1 he } 835 1.1 he 836 1.1 he ccb->ccb_state = CISS_CCB_READY; 837 1.1 he 838 1.1 he if (ccb->ccb_cmd.id & CISS_CMD_ERR) 839 1.48 jdolecek error = ciss_error(sc, ccb); 840 1.1 he 841 1.2 martti cmd = &ccb->ccb_cmd; 842 1.1 he if (ccb->ccb_data) { 843 1.1 he bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap, 0, 844 1.2 martti ccb->ccb_dmamap->dm_mapsize, (cmd->flags & CISS_CDB_IN) ? 845 1.2 martti BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); 846 1.1 he bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap); 847 1.1 he ccb->ccb_xs = NULL; 848 1.1 he ccb->ccb_data = NULL; 849 1.1 he } 850 1.1 he 851 1.48 jdolecek ciss_put_ccb(sc, ccb); 852 1.1 he 853 1.1 he if (xs) { 854 1.1 he xs->resid = 0; 855 1.1 he CISS_DPRINTF(CISS_D_CMD, ("scsipi_done(%p) ", xs)); 856 1.23 mhitch if (xs->cmd->opcode == INQUIRY) { 857 1.23 mhitch struct scsipi_inquiry_data *inq; 858 1.23 mhitch inq = (struct scsipi_inquiry_data *)xs->data; 859 1.23 mhitch if ((inq->version & SID_ANSII) == 0 && 860 1.23 mhitch (inq->flags3 & SID_CmdQue) != 0) { 861 1.23 mhitch inq->version |= 2; 862 1.23 mhitch } 863 1.23 mhitch } 864 1.1 he scsipi_done(xs); 865 1.1 he } 866 1.1 he 867 1.1 he return error; 868 1.1 he } 869 1.1 he 870 1.1 he static int 871 1.48 jdolecek ciss_error(struct ciss_softc *sc, struct ciss_ccb *ccb) 872 1.1 he { 873 1.1 he struct ciss_error *err = &ccb->ccb_err; 874 1.1 he struct scsipi_xfer *xs = ccb->ccb_xs; 875 1.1 he int rv; 876 1.1 he 877 1.1 he switch ((rv = le16toh(err->cmd_stat))) { 878 1.1 he case CISS_ERR_OK: 879 1.30 christos rv = 0; 880 1.1 he break; 881 1.1 he 882 1.1 he case CISS_ERR_INVCMD: 883 1.23 mhitch if (xs == NULL || 884 1.23 mhitch xs->cmd->opcode != SCSI_SYNCHRONIZE_CACHE_10) 885 1.23 mhitch printf("%s: invalid cmd 0x%x: 0x%x is not valid @ 0x%x[%d]\n", 886 1.29 chs device_xname(sc->sc_dev), ccb->ccb_cmd.id, 887 1.23 mhitch err->err_info, err->err_type[3], err->err_type[2]); 888 1.1 he if (xs) { 889 1.16 cegger memset(&xs->sense, 0, sizeof(xs->sense)); 890 1.1 he xs->sense.scsi_sense.response_code = 891 1.1 he SSD_RCODE_CURRENT | SSD_RCODE_VALID; 892 1.1 he xs->sense.scsi_sense.flags = SKEY_ILLEGAL_REQUEST; 893 1.1 he xs->sense.scsi_sense.asc = 0x24; /* ill field */ 894 1.1 he xs->sense.scsi_sense.ascq = 0x0; 895 1.1 he xs->error = XS_SENSE; 896 1.1 he } 897 1.30 christos rv = EIO; 898 1.1 he break; 899 1.1 he 900 1.1 he case CISS_ERR_TMO: 901 1.1 he xs->error = XS_TIMEOUT; 902 1.30 christos rv = ETIMEDOUT; 903 1.1 he break; 904 1.1 he 905 1.1 he case CISS_ERR_UNRUN: 906 1.1 he /* Underrun */ 907 1.1 he xs->resid = le32toh(err->resid); 908 1.1 he CISS_DPRINTF(CISS_D_CMD, (" underrun resid=0x%x ", 909 1.1 he xs->resid)); 910 1.30 christos rv = EIO; 911 1.1 he break; 912 1.1 he default: 913 1.1 he if (xs) { 914 1.1 he CISS_DPRINTF(CISS_D_CMD, ("scsi_stat=%x ", err->scsi_stat)); 915 1.1 he switch (err->scsi_stat) { 916 1.1 he case SCSI_CHECK: 917 1.1 he xs->error = XS_SENSE; 918 1.18 tsutsui memcpy(&xs->sense, &err->sense[0], 919 1.1 he sizeof(xs->sense)); 920 1.1 he CISS_DPRINTF(CISS_D_CMD, (" sense=%02x %02x %02x %02x ", 921 1.1 he err->sense[0], err->sense[1], err->sense[2], err->sense[3])); 922 1.30 christos rv = EIO; 923 1.1 he break; 924 1.1 he 925 1.1 he case XS_BUSY: 926 1.1 he xs->error = XS_BUSY; 927 1.30 christos rv = EBUSY; 928 1.1 he break; 929 1.1 he 930 1.1 he default: 931 1.1 he CISS_DPRINTF(CISS_D_ERR, ("%s: " 932 1.1 he "cmd_stat=%x scsi_stat=0x%x resid=0x%x\n", 933 1.29 chs device_xname(sc->sc_dev), rv, err->scsi_stat, 934 1.1 he le32toh(err->resid))); 935 1.1 he printf("ciss driver stuffup in %s:%d: %s()\n", 936 1.10 perry __FILE__, __LINE__, __func__); 937 1.1 he xs->error = XS_DRIVER_STUFFUP; 938 1.30 christos rv = EIO; 939 1.1 he break; 940 1.1 he } 941 1.1 he xs->resid = le32toh(err->resid); 942 1.30 christos } else 943 1.30 christos rv = EIO; 944 1.1 he } 945 1.1 he ccb->ccb_cmd.id &= htole32(~3); 946 1.1 he 947 1.1 he return rv; 948 1.1 he } 949 1.1 he 950 1.1 he static int 951 1.1 he ciss_inq(struct ciss_softc *sc, struct ciss_inquiry *inq) 952 1.1 he { 953 1.1 he struct ciss_ccb *ccb; 954 1.1 he struct ciss_cmd *cmd; 955 1.1 he 956 1.1 he ccb = ciss_get_ccb(sc); 957 1.1 he ccb->ccb_len = sizeof(*inq); 958 1.1 he ccb->ccb_data = inq; 959 1.2 martti ccb->ccb_xs = NULL; 960 1.1 he cmd = &ccb->ccb_cmd; 961 1.1 he cmd->tgt = htole32(CISS_CMD_MODE_PERIPH); 962 1.1 he cmd->tgt2 = 0; 963 1.1 he cmd->cdblen = 10; 964 1.1 he cmd->flags = CISS_CDB_CMD | CISS_CDB_SIMPL | CISS_CDB_IN; 965 1.1 he cmd->tmo = htole16(0); 966 1.16 cegger memset(&cmd->cdb[0], 0, sizeof(cmd->cdb)); 967 1.1 he cmd->cdb[0] = CISS_CMD_CTRL_GET; 968 1.1 he cmd->cdb[6] = CISS_CMS_CTRL_CTRL; 969 1.1 he cmd->cdb[7] = sizeof(*inq) >> 8; /* biiiig endian */ 970 1.1 he cmd->cdb[8] = sizeof(*inq) & 0xff; 971 1.1 he 972 1.48 jdolecek return ciss_cmd(sc, ccb, BUS_DMA_NOWAIT, XS_CTL_POLL|XS_CTL_NOSLEEP); 973 1.1 he } 974 1.1 he 975 1.1 he static int 976 1.1 he ciss_ldmap(struct ciss_softc *sc) 977 1.1 he { 978 1.1 he struct ciss_ccb *ccb; 979 1.1 he struct ciss_cmd *cmd; 980 1.1 he struct ciss_ldmap *lmap; 981 1.1 he int total, rv; 982 1.1 he 983 1.12 mhitch mutex_enter(&sc->sc_mutex_scratch); 984 1.1 he lmap = sc->scratch; 985 1.1 he lmap->size = htobe32(sc->maxunits * sizeof(lmap->map)); 986 1.1 he total = sizeof(*lmap) + (sc->maxunits - 1) * sizeof(lmap->map); 987 1.1 he 988 1.1 he ccb = ciss_get_ccb(sc); 989 1.1 he ccb->ccb_len = total; 990 1.1 he ccb->ccb_data = lmap; 991 1.2 martti ccb->ccb_xs = NULL; 992 1.1 he cmd = &ccb->ccb_cmd; 993 1.1 he cmd->tgt = CISS_CMD_MODE_PERIPH; 994 1.1 he cmd->tgt2 = 0; 995 1.1 he cmd->cdblen = 12; 996 1.1 he cmd->flags = CISS_CDB_CMD | CISS_CDB_SIMPL | CISS_CDB_IN; 997 1.1 he cmd->tmo = htole16(30); 998 1.16 cegger memset(&cmd->cdb[0], 0, sizeof(cmd->cdb)); 999 1.1 he cmd->cdb[0] = CISS_CMD_LDMAP; 1000 1.1 he cmd->cdb[8] = total >> 8; /* biiiig endian */ 1001 1.1 he cmd->cdb[9] = total & 0xff; 1002 1.1 he 1003 1.48 jdolecek rv = ciss_cmd(sc, ccb, BUS_DMA_NOWAIT, XS_CTL_POLL|XS_CTL_NOSLEEP); 1004 1.1 he 1005 1.12 mhitch if (rv) { 1006 1.12 mhitch mutex_exit(&sc->sc_mutex_scratch); 1007 1.1 he return rv; 1008 1.12 mhitch } 1009 1.1 he 1010 1.1 he CISS_DPRINTF(CISS_D_MISC, ("lmap %x:%x\n", 1011 1.1 he lmap->map[0].tgt, lmap->map[0].tgt2)); 1012 1.1 he 1013 1.12 mhitch mutex_exit(&sc->sc_mutex_scratch); 1014 1.1 he return 0; 1015 1.1 he } 1016 1.1 he 1017 1.1 he static int 1018 1.1 he ciss_sync(struct ciss_softc *sc) 1019 1.1 he { 1020 1.1 he struct ciss_ccb *ccb; 1021 1.1 he struct ciss_cmd *cmd; 1022 1.1 he struct ciss_flush *flush; 1023 1.1 he int rv; 1024 1.1 he 1025 1.12 mhitch mutex_enter(&sc->sc_mutex_scratch); 1026 1.1 he flush = sc->scratch; 1027 1.16 cegger memset(flush, 0, sizeof(*flush)); 1028 1.1 he flush->flush = sc->sc_flush; 1029 1.1 he 1030 1.1 he ccb = ciss_get_ccb(sc); 1031 1.1 he ccb->ccb_len = sizeof(*flush); 1032 1.1 he ccb->ccb_data = flush; 1033 1.2 martti ccb->ccb_xs = NULL; 1034 1.1 he cmd = &ccb->ccb_cmd; 1035 1.1 he cmd->tgt = CISS_CMD_MODE_PERIPH; 1036 1.1 he cmd->tgt2 = 0; 1037 1.1 he cmd->cdblen = 10; 1038 1.1 he cmd->flags = CISS_CDB_CMD | CISS_CDB_SIMPL | CISS_CDB_OUT; 1039 1.1 he cmd->tmo = 0; 1040 1.16 cegger memset(&cmd->cdb[0], 0, sizeof(cmd->cdb)); 1041 1.1 he cmd->cdb[0] = CISS_CMD_CTRL_SET; 1042 1.1 he cmd->cdb[6] = CISS_CMS_CTRL_FLUSH; 1043 1.1 he cmd->cdb[7] = sizeof(*flush) >> 8; /* biiiig endian */ 1044 1.1 he cmd->cdb[8] = sizeof(*flush) & 0xff; 1045 1.1 he 1046 1.48 jdolecek rv = ciss_cmd(sc, ccb, BUS_DMA_NOWAIT, XS_CTL_POLL|XS_CTL_NOSLEEP); 1047 1.12 mhitch mutex_exit(&sc->sc_mutex_scratch); 1048 1.1 he 1049 1.1 he return rv; 1050 1.1 he } 1051 1.1 he 1052 1.12 mhitch int 1053 1.12 mhitch ciss_ldid(struct ciss_softc *sc, int target, struct ciss_ldid *id) 1054 1.12 mhitch { 1055 1.12 mhitch struct ciss_ccb *ccb; 1056 1.12 mhitch struct ciss_cmd *cmd; 1057 1.12 mhitch 1058 1.12 mhitch ccb = ciss_get_ccb(sc); 1059 1.12 mhitch if (ccb == NULL) 1060 1.12 mhitch return ENOMEM; 1061 1.12 mhitch ccb->ccb_len = sizeof(*id); 1062 1.12 mhitch ccb->ccb_data = id; 1063 1.12 mhitch ccb->ccb_xs = NULL; 1064 1.12 mhitch cmd = &ccb->ccb_cmd; 1065 1.12 mhitch cmd->tgt = htole32(CISS_CMD_MODE_PERIPH); 1066 1.12 mhitch cmd->tgt2 = 0; 1067 1.12 mhitch cmd->cdblen = 10; 1068 1.12 mhitch cmd->flags = CISS_CDB_CMD | CISS_CDB_SIMPL | CISS_CDB_IN; 1069 1.12 mhitch cmd->tmo = htole16(0); 1070 1.16 cegger memset(&cmd->cdb[0], 0, sizeof(cmd->cdb)); 1071 1.12 mhitch cmd->cdb[0] = CISS_CMD_CTRL_GET; 1072 1.12 mhitch cmd->cdb[1] = target; 1073 1.12 mhitch cmd->cdb[6] = CISS_CMS_CTRL_LDIDEXT; 1074 1.12 mhitch cmd->cdb[7] = sizeof(*id) >> 8; /* biiiig endian */ 1075 1.12 mhitch cmd->cdb[8] = sizeof(*id) & 0xff; 1076 1.12 mhitch 1077 1.48 jdolecek return ciss_cmd(sc, ccb, BUS_DMA_NOWAIT, XS_CTL_POLL | sc->sc_waitflag); 1078 1.12 mhitch } 1079 1.12 mhitch 1080 1.12 mhitch int 1081 1.12 mhitch ciss_ldstat(struct ciss_softc *sc, int target, struct ciss_ldstat *stat) 1082 1.12 mhitch { 1083 1.12 mhitch struct ciss_ccb *ccb; 1084 1.12 mhitch struct ciss_cmd *cmd; 1085 1.12 mhitch 1086 1.12 mhitch ccb = ciss_get_ccb(sc); 1087 1.12 mhitch if (ccb == NULL) 1088 1.12 mhitch return ENOMEM; 1089 1.12 mhitch ccb->ccb_len = sizeof(*stat); 1090 1.12 mhitch ccb->ccb_data = stat; 1091 1.12 mhitch ccb->ccb_xs = NULL; 1092 1.12 mhitch cmd = &ccb->ccb_cmd; 1093 1.12 mhitch cmd->tgt = htole32(CISS_CMD_MODE_PERIPH); 1094 1.12 mhitch cmd->tgt2 = 0; 1095 1.12 mhitch cmd->cdblen = 10; 1096 1.12 mhitch cmd->flags = CISS_CDB_CMD | CISS_CDB_SIMPL | CISS_CDB_IN; 1097 1.12 mhitch cmd->tmo = htole16(0); 1098 1.16 cegger memset(&cmd->cdb[0], 0, sizeof(cmd->cdb)); 1099 1.12 mhitch cmd->cdb[0] = CISS_CMD_CTRL_GET; 1100 1.12 mhitch cmd->cdb[1] = target; 1101 1.12 mhitch cmd->cdb[6] = CISS_CMS_CTRL_LDSTAT; 1102 1.12 mhitch cmd->cdb[7] = sizeof(*stat) >> 8; /* biiiig endian */ 1103 1.12 mhitch cmd->cdb[8] = sizeof(*stat) & 0xff; 1104 1.12 mhitch 1105 1.48 jdolecek return ciss_cmd(sc, ccb, BUS_DMA_NOWAIT, XS_CTL_POLL | sc->sc_waitflag); 1106 1.12 mhitch } 1107 1.12 mhitch 1108 1.12 mhitch int 1109 1.12 mhitch ciss_pdid(struct ciss_softc *sc, u_int8_t drv, struct ciss_pdid *id, int wait) 1110 1.12 mhitch { 1111 1.12 mhitch struct ciss_ccb *ccb; 1112 1.12 mhitch struct ciss_cmd *cmd; 1113 1.12 mhitch 1114 1.12 mhitch ccb = ciss_get_ccb(sc); 1115 1.12 mhitch if (ccb == NULL) 1116 1.12 mhitch return ENOMEM; 1117 1.12 mhitch ccb->ccb_len = sizeof(*id); 1118 1.12 mhitch ccb->ccb_data = id; 1119 1.12 mhitch ccb->ccb_xs = NULL; 1120 1.12 mhitch cmd = &ccb->ccb_cmd; 1121 1.12 mhitch cmd->tgt = htole32(CISS_CMD_MODE_PERIPH); 1122 1.12 mhitch cmd->tgt2 = 0; 1123 1.12 mhitch cmd->cdblen = 10; 1124 1.12 mhitch cmd->flags = CISS_CDB_CMD | CISS_CDB_SIMPL | CISS_CDB_IN; 1125 1.12 mhitch cmd->tmo = htole16(0); 1126 1.16 cegger memset(&cmd->cdb[0], 0, sizeof(cmd->cdb)); 1127 1.12 mhitch cmd->cdb[0] = CISS_CMD_CTRL_GET; 1128 1.12 mhitch cmd->cdb[2] = drv; 1129 1.12 mhitch cmd->cdb[6] = CISS_CMS_CTRL_PDID; 1130 1.12 mhitch cmd->cdb[7] = sizeof(*id) >> 8; /* biiiig endian */ 1131 1.12 mhitch cmd->cdb[8] = sizeof(*id) & 0xff; 1132 1.12 mhitch 1133 1.48 jdolecek return ciss_cmd(sc, ccb, BUS_DMA_NOWAIT, wait); 1134 1.12 mhitch } 1135 1.12 mhitch 1136 1.12 mhitch 1137 1.12 mhitch struct ciss_ld * 1138 1.12 mhitch ciss_pdscan(struct ciss_softc *sc, int ld) 1139 1.12 mhitch { 1140 1.12 mhitch struct ciss_pdid *pdid; 1141 1.12 mhitch struct ciss_ld *ldp; 1142 1.12 mhitch u_int8_t drv, buf[128]; 1143 1.12 mhitch int i, j, k = 0; 1144 1.12 mhitch 1145 1.12 mhitch mutex_enter(&sc->sc_mutex_scratch); 1146 1.12 mhitch pdid = sc->scratch; 1147 1.14 he if (sc->ndrives == 256) { 1148 1.14 he for (i = 0; i < CISS_BIGBIT; i++) 1149 1.36 msaitoh if (!ciss_pdid(sc, i, pdid, 1150 1.14 he XS_CTL_POLL|XS_CTL_NOSLEEP) && 1151 1.14 he (pdid->present & CISS_PD_PRESENT)) 1152 1.14 he buf[k++] = i; 1153 1.14 he } else 1154 1.14 he for (i = 0; i < sc->nbus; i++) 1155 1.14 he for (j = 0; j < sc->ndrives; j++) { 1156 1.14 he drv = CISS_BIGBIT + i * sc->ndrives + j; 1157 1.14 he if (!ciss_pdid(sc, drv, pdid, 1158 1.14 he XS_CTL_POLL|XS_CTL_NOSLEEP)) 1159 1.14 he buf[k++] = drv; 1160 1.14 he } 1161 1.12 mhitch mutex_exit(&sc->sc_mutex_scratch); 1162 1.12 mhitch 1163 1.12 mhitch if (!k) 1164 1.12 mhitch return NULL; 1165 1.12 mhitch 1166 1.41 chs ldp = malloc(sizeof(*ldp) + (k-1), M_DEVBUF, M_WAITOK); 1167 1.16 cegger memset(&ldp->bling, 0, sizeof(ldp->bling)); 1168 1.12 mhitch ldp->ndrives = k; 1169 1.12 mhitch ldp->xname[0] = 0; 1170 1.18 tsutsui memcpy(ldp->tgts, buf, k); 1171 1.12 mhitch return ldp; 1172 1.12 mhitch } 1173 1.12 mhitch 1174 1.1 he static void 1175 1.1 he ciss_scsi_cmd(struct scsipi_channel *chan, scsipi_adapter_req_t req, 1176 1.1 he void *arg) 1177 1.1 he { 1178 1.23 mhitch struct scsipi_xfer *xs; 1179 1.23 mhitch struct scsipi_xfer_mode *xm; 1180 1.31 christos struct ciss_softc *sc = device_private(chan->chan_adapter->adapt_dev); 1181 1.1 he u_int8_t target; 1182 1.1 he struct ciss_ccb *ccb; 1183 1.1 he struct ciss_cmd *cmd; 1184 1.1 he 1185 1.1 he CISS_DPRINTF(CISS_D_CMD, ("ciss_scsi_cmd ")); 1186 1.1 he 1187 1.1 he switch (req) 1188 1.1 he { 1189 1.1 he case ADAPTER_REQ_RUN_XFER: 1190 1.23 mhitch xs = (struct scsipi_xfer *) arg; 1191 1.1 he target = xs->xs_periph->periph_target; 1192 1.1 he CISS_DPRINTF(CISS_D_CMD, ("targ=%d ", target)); 1193 1.1 he if (xs->cmdlen > CISS_MAX_CDB) { 1194 1.1 he CISS_DPRINTF(CISS_D_CMD, ("CDB too big %p ", xs)); 1195 1.16 cegger memset(&xs->sense, 0, sizeof(xs->sense)); 1196 1.30 christos xs->error = XS_SENSE; 1197 1.1 he printf("ciss driver stuffup in %s:%d: %s()\n", 1198 1.10 perry __FILE__, __LINE__, __func__); 1199 1.1 he scsipi_done(xs); 1200 1.1 he break; 1201 1.1 he } 1202 1.1 he 1203 1.1 he xs->error = XS_NOERROR; 1204 1.1 he 1205 1.1 he /* XXX emulate SYNCHRONIZE_CACHE ??? */ 1206 1.1 he 1207 1.1 he ccb = ciss_get_ccb(sc); 1208 1.1 he cmd = &ccb->ccb_cmd; 1209 1.1 he ccb->ccb_len = xs->datalen; 1210 1.1 he ccb->ccb_data = xs->data; 1211 1.1 he ccb->ccb_xs = xs; 1212 1.1 he cmd->tgt = CISS_CMD_MODE_LD | target; 1213 1.1 he cmd->tgt2 = 0; 1214 1.1 he cmd->cdblen = xs->cmdlen; 1215 1.1 he cmd->flags = CISS_CDB_CMD | CISS_CDB_SIMPL; 1216 1.1 he if (xs->xs_control & XS_CTL_DATA_IN) 1217 1.1 he cmd->flags |= CISS_CDB_IN; 1218 1.1 he else if (xs->xs_control & XS_CTL_DATA_OUT) 1219 1.1 he cmd->flags |= CISS_CDB_OUT; 1220 1.30 christos cmd->tmo = htole16(xs->timeout < 1000? 1 : xs->timeout / 1000); 1221 1.46 jdolecek memcpy(&cmd->cdb[0], xs->cmd, xs->cmdlen); 1222 1.1 he CISS_DPRINTF(CISS_D_CMD, ("cmd=%02x %02x %02x %02x %02x %02x ", 1223 1.1 he cmd->cdb[0], cmd->cdb[1], cmd->cdb[2], 1224 1.1 he cmd->cdb[3], cmd->cdb[4], cmd->cdb[5])); 1225 1.1 he 1226 1.48 jdolecek if (ciss_cmd(sc, ccb, BUS_DMA_WAITOK, 1227 1.1 he xs->xs_control & (XS_CTL_POLL|XS_CTL_NOSLEEP))) { 1228 1.1 he printf("ciss driver stuffup in %s:%d: %s()\n", 1229 1.10 perry __FILE__, __LINE__, __func__); 1230 1.1 he xs->error = XS_DRIVER_STUFFUP; 1231 1.1 he scsipi_done(xs); 1232 1.1 he return; 1233 1.1 he } 1234 1.1 he 1235 1.1 he break; 1236 1.1 he case ADAPTER_REQ_GROW_RESOURCES: 1237 1.1 he /* 1238 1.1 he * Not supported. 1239 1.1 he */ 1240 1.1 he break; 1241 1.1 he case ADAPTER_REQ_SET_XFER_MODE: 1242 1.1 he /* 1243 1.1 he * We can't change the transfer mode, but at least let 1244 1.55 andvar * scsipi know what the adapter has negotiated. 1245 1.1 he */ 1246 1.23 mhitch xm = (struct scsipi_xfer_mode *)arg; 1247 1.23 mhitch xm->xm_mode |= PERIPH_CAP_TQING; 1248 1.23 mhitch scsipi_async_event(chan, ASYNC_EVENT_XFER_MODE, xm); 1249 1.1 he break; 1250 1.31 christos default: 1251 1.31 christos printf("%s: %d %d unsupported\n", __func__, __LINE__, req); 1252 1.1 he } 1253 1.1 he } 1254 1.1 he 1255 1.44 jdolecek static void 1256 1.44 jdolecek ciss_completed_process(struct ciss_softc *sc, ciss_queue_head *q) 1257 1.1 he { 1258 1.1 he struct ciss_ccb *ccb; 1259 1.1 he 1260 1.50 jdolecek while (!TAILQ_EMPTY(q)) { 1261 1.50 jdolecek ccb = TAILQ_FIRST(q); 1262 1.50 jdolecek TAILQ_REMOVE(q, ccb, ccb_link); 1263 1.1 he 1264 1.1 he if (ccb->ccb_state == CISS_CCB_POLL) { 1265 1.1 he ccb->ccb_state = CISS_CCB_ONQ; 1266 1.12 mhitch mutex_enter(&sc->sc_mutex); 1267 1.12 mhitch cv_broadcast(&sc->sc_condvar); 1268 1.12 mhitch mutex_exit(&sc->sc_mutex); 1269 1.1 he } else 1270 1.48 jdolecek ciss_done(sc, ccb); 1271 1.44 jdolecek } 1272 1.44 jdolecek } 1273 1.44 jdolecek 1274 1.44 jdolecek int 1275 1.44 jdolecek ciss_intr_simple_intx(void *v) 1276 1.44 jdolecek { 1277 1.44 jdolecek struct ciss_softc *sc = v; 1278 1.44 jdolecek ciss_queue_head q; 1279 1.44 jdolecek int hit = 0; 1280 1.44 jdolecek 1281 1.44 jdolecek CISS_DPRINTF(CISS_D_INTR, ("intr ")); 1282 1.44 jdolecek 1283 1.44 jdolecek /* XXX shouldn't be necessary, intr triggers only if enabled */ 1284 1.44 jdolecek if (!(bus_space_read_4(sc->sc_iot, sc->sc_ioh, CISS_ISR) & sc->iem)) 1285 1.44 jdolecek return 0; 1286 1.1 he 1287 1.50 jdolecek TAILQ_INIT(&q); 1288 1.44 jdolecek mutex_enter(&sc->sc_mutex); 1289 1.44 jdolecek ciss_completed_simple(sc, &q); 1290 1.44 jdolecek mutex_exit(&sc->sc_mutex); 1291 1.44 jdolecek 1292 1.50 jdolecek hit = (!TAILQ_EMPTY(&q)); 1293 1.44 jdolecek ciss_completed_process(sc, &q); 1294 1.1 he 1295 1.50 jdolecek KASSERT(TAILQ_EMPTY(&q)); 1296 1.1 he CISS_DPRINTF(CISS_D_INTR, ("exit\n")); 1297 1.44 jdolecek 1298 1.1 he return hit; 1299 1.1 he } 1300 1.1 he 1301 1.44 jdolecek int 1302 1.44 jdolecek ciss_intr_perf_intx(void *v) 1303 1.44 jdolecek { 1304 1.44 jdolecek struct ciss_softc *sc = v; 1305 1.44 jdolecek 1306 1.44 jdolecek CISS_DPRINTF(CISS_D_INTR, ("intr ")); 1307 1.44 jdolecek 1308 1.44 jdolecek /* Clear the interrupt and flush the bridges. Docs say that the flush 1309 1.44 jdolecek * needs to be done twice, which doesn't seem right. 1310 1.44 jdolecek */ 1311 1.44 jdolecek bus_space_read_4(sc->sc_iot, sc->sc_ioh, CISS_OSR); 1312 1.44 jdolecek bus_space_write_4(sc->sc_iot, sc->sc_ioh, CISS_ODC, CISS_ODC_CLEAR); 1313 1.44 jdolecek 1314 1.44 jdolecek return ciss_intr_perf_msi(sc); 1315 1.44 jdolecek } 1316 1.44 jdolecek 1317 1.44 jdolecek int 1318 1.44 jdolecek ciss_intr_perf_msi(void *v) 1319 1.44 jdolecek { 1320 1.44 jdolecek struct ciss_softc *sc = v; 1321 1.44 jdolecek ciss_queue_head q; 1322 1.44 jdolecek 1323 1.44 jdolecek CISS_DPRINTF(CISS_D_INTR, ("intr ")); 1324 1.44 jdolecek 1325 1.50 jdolecek TAILQ_INIT(&q); 1326 1.44 jdolecek mutex_enter(&sc->sc_mutex); 1327 1.44 jdolecek ciss_completed_perf(sc, &q); 1328 1.44 jdolecek mutex_exit(&sc->sc_mutex); 1329 1.44 jdolecek 1330 1.44 jdolecek ciss_completed_process(sc, &q); 1331 1.44 jdolecek 1332 1.50 jdolecek KASSERT(TAILQ_EMPTY(&q)); 1333 1.44 jdolecek CISS_DPRINTF(CISS_D_INTR, ("exit")); 1334 1.44 jdolecek 1335 1.44 jdolecek return 1; 1336 1.44 jdolecek } 1337 1.44 jdolecek 1338 1.1 he static void 1339 1.1 he ciss_heartbeat(void *v) 1340 1.1 he { 1341 1.1 he struct ciss_softc *sc = v; 1342 1.1 he u_int32_t hb; 1343 1.1 he 1344 1.1 he hb = bus_space_read_4(sc->sc_iot, sc->cfg_ioh, 1345 1.1 he sc->cfgoff + offsetof(struct ciss_config, heartbeat)); 1346 1.30 christos if (hb == sc->heartbeat) { 1347 1.30 christos sc->fibrillation++; 1348 1.30 christos CISS_DPRINTF(CISS_D_ERR, ("%s: fibrillation #%d (value=%d)\n", 1349 1.30 christos device_xname(sc->sc_dev), sc->fibrillation, hb)); 1350 1.30 christos if (sc->fibrillation >= 11) { 1351 1.30 christos /* No heartbeat for 33 seconds */ 1352 1.30 christos panic("%s: dead", device_xname(sc->sc_dev)); /* XXX reset! */ 1353 1.30 christos } 1354 1.30 christos } else { 1355 1.1 he sc->heartbeat = hb; 1356 1.30 christos if (sc->fibrillation) { 1357 1.30 christos CISS_DPRINTF(CISS_D_ERR, ("%s: " 1358 1.30 christos "fibrillation ended (value=%d)\n", 1359 1.30 christos device_xname(sc->sc_dev), hb)); 1360 1.30 christos } 1361 1.30 christos sc->fibrillation = 0; 1362 1.30 christos } 1363 1.1 he 1364 1.1 he callout_schedule(&sc->sc_hb, hz * 3); 1365 1.1 he } 1366 1.1 he 1367 1.1 he static int 1368 1.6 christos ciss_scsi_ioctl(struct scsipi_channel *chan, u_long cmd, 1369 1.7 christos void *addr, int flag, struct proc *p) 1370 1.1 he { 1371 1.1 he #if NBIO > 0 1372 1.1 he return ciss_ioctl(chan->chan_adapter->adapt_dev, cmd, addr); 1373 1.1 he #else 1374 1.1 he return ENOTTY; 1375 1.1 he #endif 1376 1.1 he } 1377 1.1 he 1378 1.1 he #if NBIO > 0 1379 1.12 mhitch const int ciss_level[] = { 0, 4, 1, 5, 51, 7 }; 1380 1.12 mhitch const int ciss_stat[] = { BIOC_SVONLINE, BIOC_SVOFFLINE, BIOC_SVOFFLINE, 1381 1.12 mhitch BIOC_SVDEGRADED, BIOC_SVREBUILD, BIOC_SVREBUILD, BIOC_SVDEGRADED, 1382 1.12 mhitch BIOC_SVDEGRADED, BIOC_SVINVALID, BIOC_SVINVALID, BIOC_SVBUILDING, 1383 1.12 mhitch BIOC_SVOFFLINE, BIOC_SVBUILDING }; 1384 1.12 mhitch 1385 1.12 mhitch int 1386 1.19 cegger ciss_ioctl(device_t dev, u_long cmd, void *addr) 1387 1.1 he { 1388 1.31 christos struct ciss_softc *sc = device_private(dev); 1389 1.12 mhitch struct bioc_inq *bi; 1390 1.12 mhitch struct bioc_disk *bd; 1391 1.12 mhitch struct bioc_blink *bb; 1392 1.12 mhitch struct ciss_ldstat *ldstat; 1393 1.12 mhitch struct ciss_pdid *pdid; 1394 1.12 mhitch struct ciss_blink *blink; 1395 1.12 mhitch struct ciss_ld *ldp; 1396 1.14 he u_int8_t drv; 1397 1.12 mhitch int ld, pd, error = 0; 1398 1.1 he 1399 1.1 he switch (cmd) { 1400 1.1 he case BIOCINQ: 1401 1.12 mhitch bi = (struct bioc_inq *)addr; 1402 1.29 chs strlcpy(bi->bi_dev, device_xname(sc->sc_dev), sizeof(bi->bi_dev)); 1403 1.12 mhitch bi->bi_novol = sc->maxunits; 1404 1.12 mhitch bi->bi_nodisk = sc->sc_lds[0]->ndrives; 1405 1.12 mhitch break; 1406 1.12 mhitch 1407 1.1 he case BIOCVOL: 1408 1.12 mhitch error = ciss_ioctl_vol(sc, (struct bioc_vol *)addr); 1409 1.12 mhitch break; 1410 1.12 mhitch 1411 1.12 mhitch case BIOCDISK_NOVOL: 1412 1.12 mhitch /* 1413 1.12 mhitch * XXX since we don't know how to associate physical drives with logical drives 1414 1.12 mhitch * yet, BIOCDISK_NOVOL is equivalent to BIOCDISK to the volume that we've 1415 1.12 mhitch * associated all physical drives to. 1416 1.53 msaitoh * Maybe associate all physical drives to all logical volumes, but only return 1417 1.12 mhitch * physical drives on one logical volume. Which one? Either 1st volume that 1418 1.12 mhitch * is degraded, rebuilding, or failed? 1419 1.12 mhitch */ 1420 1.12 mhitch bd = (struct bioc_disk *)addr; 1421 1.12 mhitch bd->bd_volid = 0; 1422 1.12 mhitch bd->bd_disknovol = true; 1423 1.12 mhitch /* FALLTHROUGH */ 1424 1.1 he case BIOCDISK: 1425 1.12 mhitch bd = (struct bioc_disk *)addr; 1426 1.37 riastrad if (bd->bd_volid < 0 || bd->bd_volid > sc->maxunits) { 1427 1.12 mhitch error = EINVAL; 1428 1.12 mhitch break; 1429 1.12 mhitch } 1430 1.12 mhitch ldp = sc->sc_lds[0]; 1431 1.37 riastrad if (!ldp || (pd = bd->bd_diskid) < 0 || pd > ldp->ndrives) { 1432 1.12 mhitch error = EINVAL; 1433 1.12 mhitch break; 1434 1.12 mhitch } 1435 1.12 mhitch ldstat = sc->scratch; 1436 1.12 mhitch if ((error = ciss_ldstat(sc, bd->bd_volid, ldstat))) { 1437 1.12 mhitch break; 1438 1.12 mhitch } 1439 1.12 mhitch bd->bd_status = -1; 1440 1.14 he if (ldstat->stat == CISS_LD_REBLD && 1441 1.14 he ldstat->bigrebuild == ldp->tgts[pd]) 1442 1.12 mhitch bd->bd_status = BIOC_SDREBUILD; 1443 1.12 mhitch if (ciss_bitset(ldp->tgts[pd] & (~CISS_BIGBIT), 1444 1.12 mhitch ldstat->bigfailed)) { 1445 1.12 mhitch bd->bd_status = BIOC_SDFAILED; 1446 1.12 mhitch bd->bd_size = 0; 1447 1.12 mhitch bd->bd_channel = (ldp->tgts[pd] & (~CISS_BIGBIT)) / 1448 1.12 mhitch sc->ndrives; 1449 1.12 mhitch bd->bd_target = ldp->tgts[pd] % sc->ndrives; 1450 1.12 mhitch bd->bd_lun = 0; 1451 1.12 mhitch bd->bd_vendor[0] = '\0'; 1452 1.12 mhitch bd->bd_serial[0] = '\0'; 1453 1.12 mhitch bd->bd_procdev[0] = '\0'; 1454 1.12 mhitch } else { 1455 1.12 mhitch pdid = sc->scratch; 1456 1.12 mhitch if ((error = ciss_pdid(sc, ldp->tgts[pd], pdid, 1457 1.12 mhitch XS_CTL_POLL))) { 1458 1.12 mhitch bd->bd_status = BIOC_SDFAILED; 1459 1.12 mhitch bd->bd_size = 0; 1460 1.12 mhitch bd->bd_channel = (ldp->tgts[pd] & (~CISS_BIGBIT)) / 1461 1.12 mhitch sc->ndrives; 1462 1.12 mhitch bd->bd_target = ldp->tgts[pd] % sc->ndrives; 1463 1.12 mhitch bd->bd_lun = 0; 1464 1.12 mhitch bd->bd_vendor[0] = '\0'; 1465 1.12 mhitch bd->bd_serial[0] = '\0'; 1466 1.12 mhitch bd->bd_procdev[0] = '\0'; 1467 1.12 mhitch error = 0; 1468 1.12 mhitch break; 1469 1.12 mhitch } 1470 1.12 mhitch if (bd->bd_status < 0) { 1471 1.12 mhitch if (pdid->config & CISS_PD_SPARE) 1472 1.12 mhitch bd->bd_status = BIOC_SDHOTSPARE; 1473 1.12 mhitch else if (pdid->present & CISS_PD_PRESENT) 1474 1.12 mhitch bd->bd_status = BIOC_SDONLINE; 1475 1.12 mhitch else 1476 1.12 mhitch bd->bd_status = BIOC_SDINVALID; 1477 1.12 mhitch } 1478 1.12 mhitch bd->bd_size = (u_int64_t)le32toh(pdid->nblocks) * 1479 1.12 mhitch le16toh(pdid->blksz); 1480 1.36 msaitoh bd->bd_channel = pdid->bus; 1481 1.12 mhitch bd->bd_target = pdid->target; 1482 1.12 mhitch bd->bd_lun = 0; 1483 1.12 mhitch strlcpy(bd->bd_vendor, pdid->model, 1484 1.12 mhitch sizeof(bd->bd_vendor)); 1485 1.12 mhitch strlcpy(bd->bd_serial, pdid->serial, 1486 1.12 mhitch sizeof(bd->bd_serial)); 1487 1.12 mhitch bd->bd_procdev[0] = '\0'; 1488 1.12 mhitch } 1489 1.12 mhitch break; 1490 1.12 mhitch 1491 1.12 mhitch case BIOCBLINK: 1492 1.12 mhitch bb = (struct bioc_blink *)addr; 1493 1.12 mhitch blink = sc->scratch; 1494 1.12 mhitch error = EINVAL; 1495 1.12 mhitch /* XXX workaround completely dumb scsi addressing */ 1496 1.12 mhitch for (ld = 0; ld < sc->maxunits; ld++) { 1497 1.12 mhitch ldp = sc->sc_lds[ld]; 1498 1.12 mhitch if (!ldp) 1499 1.12 mhitch continue; 1500 1.14 he if (sc->ndrives == 256) 1501 1.14 he drv = bb->bb_target; 1502 1.14 he else 1503 1.14 he drv = CISS_BIGBIT + 1504 1.14 he bb->bb_channel * sc->ndrives + 1505 1.14 he bb->bb_target; 1506 1.12 mhitch for (pd = 0; pd < ldp->ndrives; pd++) 1507 1.14 he if (ldp->tgts[pd] == drv) 1508 1.12 mhitch error = ciss_blink(sc, ld, pd, 1509 1.12 mhitch bb->bb_status, blink); 1510 1.12 mhitch } 1511 1.12 mhitch break; 1512 1.12 mhitch 1513 1.1 he default: 1514 1.12 mhitch error = EINVAL; 1515 1.1 he } 1516 1.1 he 1517 1.12 mhitch return (error); 1518 1.12 mhitch } 1519 1.12 mhitch 1520 1.12 mhitch int 1521 1.12 mhitch ciss_ioctl_vol(struct ciss_softc *sc, struct bioc_vol *bv) 1522 1.12 mhitch { 1523 1.12 mhitch struct ciss_ldid *ldid; 1524 1.12 mhitch struct ciss_ld *ldp; 1525 1.12 mhitch struct ciss_ldstat *ldstat; 1526 1.12 mhitch struct ciss_pdid *pdid; 1527 1.12 mhitch int error = 0; 1528 1.12 mhitch u_int blks; 1529 1.12 mhitch 1530 1.37 riastrad if (bv->bv_volid < 0 || bv->bv_volid > sc->maxunits) { 1531 1.12 mhitch return EINVAL; 1532 1.12 mhitch } 1533 1.12 mhitch ldp = sc->sc_lds[bv->bv_volid]; 1534 1.12 mhitch ldid = sc->scratch; 1535 1.12 mhitch if ((error = ciss_ldid(sc, bv->bv_volid, ldid))) { 1536 1.12 mhitch return error; 1537 1.12 mhitch } 1538 1.12 mhitch bv->bv_status = BIOC_SVINVALID; 1539 1.12 mhitch blks = (u_int)le16toh(ldid->nblocks[1]) << 16 | 1540 1.12 mhitch le16toh(ldid->nblocks[0]); 1541 1.12 mhitch bv->bv_size = blks * (u_quad_t)le16toh(ldid->blksize); 1542 1.12 mhitch bv->bv_level = ciss_level[ldid->type]; 1543 1.12 mhitch /* 1544 1.55 andvar * XXX Should only return bv_nodisk for logical volume that we've associated 1545 1.12 mhitch * the physical drives to: either the 1st degraded, rebuilding, or failed 1546 1.12 mhitch * volume else volume 0? 1547 1.12 mhitch */ 1548 1.12 mhitch if (ldp) { 1549 1.12 mhitch bv->bv_nodisk = ldp->ndrives; 1550 1.12 mhitch strlcpy(bv->bv_dev, ldp->xname, sizeof(bv->bv_dev)); 1551 1.12 mhitch } 1552 1.12 mhitch strlcpy(bv->bv_vendor, "CISS", sizeof(bv->bv_vendor)); 1553 1.12 mhitch ldstat = sc->scratch; 1554 1.16 cegger memset(ldstat, 0, sizeof(*ldstat)); 1555 1.12 mhitch if ((error = ciss_ldstat(sc, bv->bv_volid, ldstat))) { 1556 1.12 mhitch return error; 1557 1.12 mhitch } 1558 1.12 mhitch bv->bv_percent = -1; 1559 1.12 mhitch bv->bv_seconds = 0; 1560 1.12 mhitch if (ldstat->stat < sizeof(ciss_stat)/sizeof(ciss_stat[0])) 1561 1.12 mhitch bv->bv_status = ciss_stat[ldstat->stat]; 1562 1.12 mhitch if (bv->bv_status == BIOC_SVREBUILD || 1563 1.12 mhitch bv->bv_status == BIOC_SVBUILDING) { 1564 1.12 mhitch u_int64_t prog; 1565 1.12 mhitch 1566 1.12 mhitch ldp = sc->sc_lds[0]; 1567 1.12 mhitch if (ldp) { 1568 1.12 mhitch bv->bv_nodisk = ldp->ndrives; 1569 1.12 mhitch strlcpy(bv->bv_dev, ldp->xname, sizeof(bv->bv_dev)); 1570 1.12 mhitch } 1571 1.12 mhitch /* 1572 1.12 mhitch * XXX ldstat->prog is blocks remaining on physical drive being rebuilt 1573 1.12 mhitch * blks is only correct for a RAID1 set; RAID5 needs to determine the 1574 1.12 mhitch * size of the physical device - which we don't yet know. 1575 1.12 mhitch * ldstat->bigrebuild has physical device target, so could be used with 1576 1.12 mhitch * pdid to get size. Another way is to save pd information in sc so it's 1577 1.12 mhitch * easy to reference. 1578 1.12 mhitch */ 1579 1.12 mhitch prog = (u_int64_t)((ldstat->prog[3] << 24) | 1580 1.12 mhitch (ldstat->prog[2] << 16) | (ldstat->prog[1] << 8) | 1581 1.12 mhitch ldstat->prog[0]); 1582 1.12 mhitch pdid = sc->scratch; 1583 1.12 mhitch if (!ciss_pdid(sc, ldstat->bigrebuild, pdid, XS_CTL_POLL)) { 1584 1.12 mhitch blks = le32toh(pdid->nblocks); 1585 1.12 mhitch bv->bv_percent = (blks - prog) * 1000ULL / blks; 1586 1.12 mhitch } 1587 1.12 mhitch } 1588 1.12 mhitch return 0; 1589 1.12 mhitch } 1590 1.12 mhitch 1591 1.12 mhitch int 1592 1.12 mhitch ciss_blink(struct ciss_softc *sc, int ld, int pd, int stat, 1593 1.12 mhitch struct ciss_blink *blink) 1594 1.12 mhitch { 1595 1.12 mhitch struct ciss_ccb *ccb; 1596 1.12 mhitch struct ciss_cmd *cmd; 1597 1.12 mhitch struct ciss_ld *ldp; 1598 1.12 mhitch 1599 1.12 mhitch if (ld > sc->maxunits) 1600 1.12 mhitch return EINVAL; 1601 1.12 mhitch 1602 1.12 mhitch ldp = sc->sc_lds[ld]; 1603 1.12 mhitch if (!ldp || pd > ldp->ndrives) 1604 1.12 mhitch return EINVAL; 1605 1.12 mhitch 1606 1.12 mhitch ldp->bling.pdtab[ldp->tgts[pd]] = stat == BIOC_SBUNBLINK? 0 : 1607 1.12 mhitch CISS_BLINK_ALL; 1608 1.18 tsutsui memcpy(blink, &ldp->bling, sizeof(*blink)); 1609 1.12 mhitch 1610 1.12 mhitch ccb = ciss_get_ccb(sc); 1611 1.12 mhitch if (ccb == NULL) 1612 1.12 mhitch return ENOMEM; 1613 1.12 mhitch ccb->ccb_len = sizeof(*blink); 1614 1.12 mhitch ccb->ccb_data = blink; 1615 1.12 mhitch ccb->ccb_xs = NULL; 1616 1.12 mhitch cmd = &ccb->ccb_cmd; 1617 1.12 mhitch cmd->tgt = htole32(CISS_CMD_MODE_PERIPH); 1618 1.12 mhitch cmd->tgt2 = 0; 1619 1.12 mhitch cmd->cdblen = 10; 1620 1.12 mhitch cmd->flags = CISS_CDB_CMD | CISS_CDB_SIMPL | CISS_CDB_OUT; 1621 1.12 mhitch cmd->tmo = htole16(0); 1622 1.16 cegger memset(&cmd->cdb[0], 0, sizeof(cmd->cdb)); 1623 1.12 mhitch cmd->cdb[0] = CISS_CMD_CTRL_SET; 1624 1.12 mhitch cmd->cdb[6] = CISS_CMS_CTRL_PDBLINK; 1625 1.12 mhitch cmd->cdb[7] = sizeof(*blink) >> 8; /* biiiig endian */ 1626 1.12 mhitch cmd->cdb[8] = sizeof(*blink) & 0xff; 1627 1.12 mhitch 1628 1.48 jdolecek return ciss_cmd(sc, ccb, BUS_DMA_NOWAIT, XS_CTL_POLL); 1629 1.12 mhitch } 1630 1.12 mhitch 1631 1.12 mhitch int 1632 1.12 mhitch ciss_create_sensors(struct ciss_softc *sc) 1633 1.12 mhitch { 1634 1.12 mhitch int i; 1635 1.12 mhitch int nsensors = sc->maxunits; 1636 1.12 mhitch 1637 1.28 chs if (nsensors == 0) { 1638 1.28 chs return 0; 1639 1.28 chs } 1640 1.28 chs 1641 1.12 mhitch sc->sc_sme = sysmon_envsys_create(); 1642 1.12 mhitch sc->sc_sensor = malloc(sizeof(envsys_data_t) * nsensors, 1643 1.41 chs M_DEVBUF, M_WAITOK | M_ZERO); 1644 1.12 mhitch 1645 1.12 mhitch for (i = 0; i < nsensors; i++) { 1646 1.12 mhitch sc->sc_sensor[i].units = ENVSYS_DRIVE; 1647 1.26 pgoyette sc->sc_sensor[i].state = ENVSYS_SINVALID; 1648 1.27 pgoyette sc->sc_sensor[i].value_cur = ENVSYS_DRIVE_EMPTY; 1649 1.12 mhitch /* Enable monitoring for drive state changes */ 1650 1.12 mhitch sc->sc_sensor[i].flags |= ENVSYS_FMONSTCHANGED; 1651 1.12 mhitch /* logical drives */ 1652 1.12 mhitch snprintf(sc->sc_sensor[i].desc, 1653 1.12 mhitch sizeof(sc->sc_sensor[i].desc), "%s:%d", 1654 1.29 chs device_xname(sc->sc_dev), i); 1655 1.12 mhitch if (sysmon_envsys_sensor_attach(sc->sc_sme, 1656 1.12 mhitch &sc->sc_sensor[i])) 1657 1.12 mhitch goto out; 1658 1.12 mhitch } 1659 1.12 mhitch 1660 1.29 chs sc->sc_sme->sme_name = device_xname(sc->sc_dev); 1661 1.12 mhitch sc->sc_sme->sme_cookie = sc; 1662 1.12 mhitch sc->sc_sme->sme_refresh = ciss_sensor_refresh; 1663 1.12 mhitch if (sysmon_envsys_register(sc->sc_sme)) { 1664 1.26 pgoyette printf("%s: unable to register with sysmon\n", 1665 1.29 chs device_xname(sc->sc_dev)); 1666 1.12 mhitch return(1); 1667 1.12 mhitch } 1668 1.12 mhitch return (0); 1669 1.12 mhitch 1670 1.12 mhitch out: 1671 1.12 mhitch free(sc->sc_sensor, M_DEVBUF); 1672 1.12 mhitch sysmon_envsys_destroy(sc->sc_sme); 1673 1.12 mhitch return EINVAL; 1674 1.12 mhitch } 1675 1.12 mhitch 1676 1.12 mhitch void 1677 1.12 mhitch ciss_sensor_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 1678 1.12 mhitch { 1679 1.12 mhitch struct ciss_softc *sc = sme->sme_cookie; 1680 1.12 mhitch struct bioc_vol bv; 1681 1.12 mhitch 1682 1.12 mhitch if (edata->sensor >= sc->maxunits) 1683 1.12 mhitch return; 1684 1.12 mhitch 1685 1.16 cegger memset(&bv, 0, sizeof(bv)); 1686 1.12 mhitch bv.bv_volid = edata->sensor; 1687 1.33 christos if (ciss_ioctl_vol(sc, &bv)) 1688 1.33 christos bv.bv_status = BIOC_SVINVALID; 1689 1.12 mhitch 1690 1.33 christos bio_vol_to_envsys(edata, &bv); 1691 1.1 he } 1692 1.12 mhitch #endif /* NBIO > 0 */ 1693