| File: | dev/pv/xbf.c |
| Warning: | line 926, column 7 Although the value stored to 'error' is used in the enclosing expression, the value is never actually read from 'error' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: xbf.c,v 1.51 2020/10/15 13:22:13 krw Exp $ */ |
| 2 | |
| 3 | /* |
| 4 | * Copyright (c) 2016, 2017 Mike Belopuhov |
| 5 | * Copyright (c) 2009, 2011 Mark Kettenis |
| 6 | * |
| 7 | * Permission to use, copy, modify, and distribute this software for any |
| 8 | * purpose with or without fee is hereby granted, provided that the above |
| 9 | * copyright notice and this permission notice appear in all copies. |
| 10 | * |
| 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
| 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
| 16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
| 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| 18 | */ |
| 19 | |
| 20 | #include "bio.h" |
| 21 | |
| 22 | #include <sys/param.h> |
| 23 | #include <sys/systm.h> |
| 24 | #include <sys/atomic.h> |
| 25 | #include <sys/device.h> |
| 26 | #include <sys/kernel.h> |
| 27 | #include <sys/buf.h> |
| 28 | #include <sys/malloc.h> |
| 29 | #include <sys/task.h> |
| 30 | |
| 31 | #include <machine/bus.h> |
| 32 | |
| 33 | #include <dev/pv/xenreg.h> |
| 34 | #include <dev/pv/xenvar.h> |
| 35 | |
| 36 | #include <scsi/scsi_all.h> |
| 37 | #include <scsi/cd.h> |
| 38 | #include <scsi/scsi_disk.h> |
| 39 | #include <scsi/scsiconf.h> |
| 40 | |
| 41 | /* #define XBF_DEBUG */ |
| 42 | |
| 43 | #ifdef XBF_DEBUG |
| 44 | #define DPRINTF(x...) printf(x) |
| 45 | #else |
| 46 | #define DPRINTF(x...) |
| 47 | #endif |
| 48 | |
| 49 | #define XBF_OP_READ0 0 |
| 50 | #define XBF_OP_WRITE1 1 |
| 51 | #define XBF_OP_BARRIER2 2 /* feature-barrier */ |
| 52 | #define XBF_OP_FLUSH3 3 /* feature-flush-cache */ |
| 53 | #define XBF_OP_DISCARD5 5 /* feature-discard */ |
| 54 | #define XBF_OP_INDIRECT6 6 /* feature-max-indirect-segments */ |
| 55 | |
| 56 | #define XBF_MAX_SGE11 11 |
| 57 | #define XBF_MAX_ISGE8 8 |
| 58 | |
| 59 | #define XBF_SEC_SHIFT9 9 |
| 60 | |
| 61 | #define XBF_CDROM1 1 |
| 62 | #define XBF_REMOVABLE2 2 |
| 63 | #define XBF_READONLY4 4 |
| 64 | |
| 65 | #define XBF_OK0 0 |
| 66 | #define XBF_EIO-1 -1 /* generic failure */ |
| 67 | #define XBF_EOPNOTSUPP-2 -2 /* only for XBF_OP_BARRIER */ |
| 68 | |
| 69 | struct xbf_sge { |
| 70 | uint32_t sge_ref; |
| 71 | uint8_t sge_first; |
| 72 | uint8_t sge_last; |
| 73 | uint16_t sge_pad; |
| 74 | } __packed__attribute__((__packed__)); |
| 75 | |
| 76 | /* Generic I/O request */ |
| 77 | struct xbf_req { |
| 78 | uint8_t req_op; |
| 79 | uint8_t req_nsegs; |
| 80 | uint16_t req_unit; |
| 81 | #ifdef __amd64__1 |
| 82 | uint32_t req_pad; |
| 83 | #endif |
| 84 | uint64_t req_id; |
| 85 | uint64_t req_sector; |
| 86 | struct xbf_sge req_sgl[XBF_MAX_SGE11]; |
| 87 | } __packed__attribute__((__packed__)); |
| 88 | |
| 89 | /* Indirect I/O request */ |
| 90 | struct xbf_ireq { |
| 91 | uint8_t req_op; |
| 92 | uint8_t req_iop; |
| 93 | uint16_t req_nsegs; |
| 94 | #ifdef __amd64__1 |
| 95 | uint32_t req_pad; |
| 96 | #endif |
| 97 | uint64_t req_id; |
| 98 | uint64_t req_sector; |
| 99 | uint16_t req_unit; |
| 100 | uint32_t req_gref[XBF_MAX_ISGE8]; |
| 101 | #ifdef __i386__ |
| 102 | uint64_t req_pad; |
| 103 | #endif |
| 104 | } __packed__attribute__((__packed__)); |
| 105 | |
| 106 | struct xbf_rsp { |
| 107 | uint64_t rsp_id; |
| 108 | uint8_t rsp_op; |
| 109 | uint8_t rsp_pad1; |
| 110 | int16_t rsp_status; |
| 111 | #ifdef __amd64__1 |
| 112 | uint32_t rsp_pad2; |
| 113 | #endif |
| 114 | } __packed__attribute__((__packed__)); |
| 115 | |
| 116 | union xbf_ring_desc { |
| 117 | struct xbf_req xrd_req; |
| 118 | struct xbf_ireq xrd_ireq; |
| 119 | struct xbf_rsp xrd_rsp; |
| 120 | } __packed__attribute__((__packed__)); |
| 121 | |
| 122 | #define XBF_MIN_RING_SIZE1 1 |
| 123 | #define XBF_MAX_RING_SIZE8 8 |
| 124 | #define XBF_MAX_REQS256 256 /* must be a power of 2 */ |
| 125 | |
| 126 | struct xbf_ring { |
| 127 | volatile uint32_t xr_prod; |
| 128 | volatile uint32_t xr_prod_event; |
| 129 | volatile uint32_t xr_cons; |
| 130 | volatile uint32_t xr_cons_event; |
| 131 | uint32_t xr_reserved[12]; |
| 132 | union xbf_ring_desc xr_desc[0]; |
| 133 | } __packed__attribute__((__packed__)); |
| 134 | |
| 135 | struct xbf_dma_mem { |
| 136 | bus_size_t dma_size; |
| 137 | bus_dma_tag_t dma_tag; |
| 138 | bus_dmamap_t dma_map; |
| 139 | bus_dma_segment_t *dma_seg; |
| 140 | int dma_nsegs; /* total amount */ |
| 141 | int dma_rsegs; /* used amount */ |
| 142 | caddr_t dma_vaddr; |
| 143 | }; |
| 144 | |
| 145 | struct xbf_ccb { |
| 146 | struct scsi_xfer *ccb_xfer; /* associated transfer */ |
| 147 | bus_dmamap_t ccb_dmap; /* transfer map */ |
| 148 | struct xbf_dma_mem ccb_bbuf; /* bounce buffer */ |
| 149 | uint32_t ccb_first; /* first descriptor */ |
| 150 | uint32_t ccb_last; /* last descriptor */ |
| 151 | uint16_t ccb_want; /* expected chunks */ |
| 152 | uint16_t ccb_seen; /* completed chunks */ |
| 153 | TAILQ_ENTRY(xbf_ccb)struct { struct xbf_ccb *tqe_next; struct xbf_ccb **tqe_prev; } ccb_link; |
| 154 | }; |
| 155 | TAILQ_HEAD(xbf_ccb_queue, xbf_ccb)struct xbf_ccb_queue { struct xbf_ccb *tqh_first; struct xbf_ccb **tqh_last; }; |
| 156 | |
| 157 | struct xbf_softc { |
| 158 | struct device sc_dev; |
| 159 | struct device *sc_parent; |
| 160 | char sc_node[XEN_MAX_NODE_LEN64]; |
| 161 | char sc_backend[XEN_MAX_BACKEND_LEN128]; |
| 162 | bus_dma_tag_t sc_dmat; |
| 163 | int sc_domid; |
| 164 | |
| 165 | xen_intr_handle_t sc_xih; |
| 166 | |
| 167 | int sc_state; |
| 168 | #define XBF_CONNECTED4 4 |
| 169 | #define XBF_CLOSING5 5 |
| 170 | |
| 171 | int sc_caps; |
| 172 | #define XBF_CAP_BARRIER0x0001 0x0001 |
| 173 | #define XBF_CAP_FLUSH0x0002 0x0002 |
| 174 | |
| 175 | uint32_t sc_type; |
| 176 | uint32_t sc_unit; |
| 177 | char sc_dtype[16]; |
| 178 | char sc_prod[16]; |
| 179 | |
| 180 | uint64_t sc_disk_size; |
| 181 | uint32_t sc_block_size; |
| 182 | |
| 183 | /* Ring */ |
| 184 | struct xbf_ring *sc_xr; |
| 185 | uint32_t sc_xr_cons; |
| 186 | uint32_t sc_xr_prod; |
| 187 | uint32_t sc_xr_size; /* in pages */ |
| 188 | struct xbf_dma_mem sc_xr_dma; |
| 189 | uint32_t sc_xr_ref[XBF_MAX_RING_SIZE8]; |
| 190 | int sc_xr_ndesc; |
| 191 | |
| 192 | /* Maximum number of blocks that one descriptor may refer to */ |
| 193 | int sc_xrd_nblk; |
| 194 | |
| 195 | /* CCBs */ |
| 196 | int sc_nccb; |
| 197 | struct xbf_ccb *sc_ccbs; |
| 198 | struct xbf_ccb_queue sc_ccb_fq; /* free queue */ |
| 199 | struct xbf_ccb_queue sc_ccb_sq; /* pending requests */ |
| 200 | struct mutex sc_ccb_fqlck; |
| 201 | struct mutex sc_ccb_sqlck; |
| 202 | |
| 203 | struct scsi_iopool sc_iopool; |
| 204 | struct device *sc_scsibus; |
| 205 | }; |
| 206 | |
| 207 | int xbf_match(struct device *, void *, void *); |
| 208 | void xbf_attach(struct device *, struct device *, void *); |
| 209 | int xbf_detach(struct device *, int); |
| 210 | |
| 211 | struct cfdriver xbf_cd = { |
| 212 | NULL((void *)0), "xbf", DV_DULL |
| 213 | }; |
| 214 | |
| 215 | const struct cfattach xbf_ca = { |
| 216 | sizeof(struct xbf_softc), xbf_match, xbf_attach, xbf_detach |
| 217 | }; |
| 218 | |
| 219 | void xbf_intr(void *); |
| 220 | |
| 221 | int xbf_load_cmd(struct scsi_xfer *); |
| 222 | int xbf_bounce_cmd(struct scsi_xfer *); |
| 223 | void xbf_reclaim_cmd(struct scsi_xfer *); |
| 224 | |
| 225 | void xbf_scsi_cmd(struct scsi_xfer *); |
| 226 | int xbf_submit_cmd(struct scsi_xfer *); |
| 227 | int xbf_poll_cmd(struct scsi_xfer *); |
| 228 | void xbf_complete_cmd(struct xbf_softc *, struct xbf_ccb_queue *, int); |
| 229 | |
| 230 | struct scsi_adapter xbf_switch = { |
| 231 | xbf_scsi_cmd, NULL((void *)0), NULL((void *)0), NULL((void *)0), NULL((void *)0) |
| 232 | }; |
| 233 | |
| 234 | void xbf_scsi_inq(struct scsi_xfer *); |
| 235 | void xbf_scsi_inquiry(struct scsi_xfer *); |
| 236 | void xbf_scsi_capacity(struct scsi_xfer *); |
| 237 | void xbf_scsi_capacity16(struct scsi_xfer *); |
| 238 | void xbf_scsi_done(struct scsi_xfer *, int); |
| 239 | |
| 240 | int xbf_dma_alloc(struct xbf_softc *, struct xbf_dma_mem *, |
| 241 | bus_size_t, int, int); |
| 242 | void xbf_dma_free(struct xbf_softc *, struct xbf_dma_mem *); |
| 243 | |
| 244 | int xbf_get_type(struct xbf_softc *); |
| 245 | int xbf_init(struct xbf_softc *); |
| 246 | int xbf_ring_create(struct xbf_softc *); |
| 247 | void xbf_ring_destroy(struct xbf_softc *); |
| 248 | void xbf_stop(struct xbf_softc *); |
| 249 | |
| 250 | int xbf_alloc_ccbs(struct xbf_softc *); |
| 251 | void xbf_free_ccbs(struct xbf_softc *); |
| 252 | void *xbf_get_ccb(void *); |
| 253 | void xbf_put_ccb(void *, void *); |
| 254 | |
| 255 | int |
| 256 | xbf_match(struct device *parent, void *match, void *aux) |
| 257 | { |
| 258 | struct xen_attach_args *xa = aux; |
| 259 | |
| 260 | if (strcmp("vbd", xa->xa_name)) |
| 261 | return (0); |
| 262 | |
| 263 | return (1); |
| 264 | } |
| 265 | |
| 266 | void |
| 267 | xbf_attach(struct device *parent, struct device *self, void *aux) |
| 268 | { |
| 269 | struct xen_attach_args *xa = aux; |
| 270 | struct xbf_softc *sc = (struct xbf_softc *)self; |
| 271 | struct scsibus_attach_args saa; |
| 272 | |
| 273 | sc->sc_parent = parent; |
| 274 | sc->sc_dmat = xa->xa_dmat; |
| 275 | sc->sc_domid = xa->xa_domid; |
| 276 | |
| 277 | memcpy(sc->sc_node, xa->xa_node, XEN_MAX_NODE_LEN)__builtin_memcpy((sc->sc_node), (xa->xa_node), (64)); |
| 278 | memcpy(sc->sc_backend, xa->xa_backend, XEN_MAX_BACKEND_LEN)__builtin_memcpy((sc->sc_backend), (xa->xa_backend), (128 )); |
| 279 | |
| 280 | if (xbf_get_type(sc)) |
| 281 | return; |
| 282 | |
| 283 | if (xen_intr_establish(0, &sc->sc_xih, sc->sc_domid, xbf_intr, sc, |
| 284 | sc->sc_dev.dv_xname)) { |
| 285 | printf(": failed to establish an interrupt\n"); |
| 286 | return; |
| 287 | } |
| 288 | xen_intr_mask(sc->sc_xih); |
| 289 | |
| 290 | printf(" backend %d channel %u: %s\n", sc->sc_domid, sc->sc_xih, |
| 291 | sc->sc_dtype); |
| 292 | |
| 293 | if (xbf_init(sc)) |
| 294 | goto error; |
| 295 | |
| 296 | if (xen_intr_unmask(sc->sc_xih)) { |
| 297 | printf("%s: failed to enable interrupts\n", |
| 298 | sc->sc_dev.dv_xname); |
| 299 | goto error; |
| 300 | } |
| 301 | |
| 302 | saa.saa_adapter = &xbf_switch; |
| 303 | saa.saa_adapter_softc = self; |
| 304 | saa.saa_adapter_buswidth = 1; |
| 305 | saa.saa_luns = 1; |
| 306 | saa.saa_adapter_target = SDEV_NO_ADAPTER_TARGET0xffff; |
| 307 | saa.saa_openings = sc->sc_nccb; |
| 308 | saa.saa_pool = &sc->sc_iopool; |
| 309 | saa.saa_quirks = saa.saa_flags = 0; |
| 310 | saa.saa_wwpn = saa.saa_wwnn = 0; |
| 311 | |
| 312 | sc->sc_scsibus = config_found(self, &saa, scsiprint)config_found_sm((self), (&saa), (scsiprint), ((void *)0)); |
| 313 | |
| 314 | xen_unplug_emulated(parent, XEN_UNPLUG_IDE0x0002 | XEN_UNPLUG_IDESEC0x0004); |
| 315 | |
| 316 | return; |
| 317 | |
| 318 | error: |
| 319 | xen_intr_disestablish(sc->sc_xih); |
| 320 | } |
| 321 | |
| 322 | int |
| 323 | xbf_detach(struct device *self, int flags) |
| 324 | { |
| 325 | struct xbf_softc *sc = (struct xbf_softc *)self; |
| 326 | int ostate = sc->sc_state; |
| 327 | |
| 328 | sc->sc_state = XBF_CLOSING5; |
| 329 | |
| 330 | xen_intr_mask(sc->sc_xih); |
| 331 | xen_intr_barrier(sc->sc_xih); |
| 332 | |
| 333 | if (ostate == XBF_CONNECTED4) { |
| 334 | xen_intr_disestablish(sc->sc_xih); |
| 335 | xbf_stop(sc); |
| 336 | } |
| 337 | |
| 338 | if (sc->sc_scsibus) |
| 339 | return (config_detach(sc->sc_scsibus, flags | DETACH_FORCE0x01)); |
| 340 | |
| 341 | return (0); |
| 342 | } |
| 343 | |
| 344 | void |
| 345 | xbf_intr(void *xsc) |
| 346 | { |
| 347 | struct xbf_softc *sc = xsc; |
| 348 | struct xbf_ring *xr = sc->sc_xr; |
| 349 | struct xbf_dma_mem *dma = &sc->sc_xr_dma; |
| 350 | struct xbf_ccb_queue cq; |
| 351 | struct xbf_ccb *ccb, *nccb; |
| 352 | uint32_t cons; |
| 353 | int desc, s; |
| 354 | |
| 355 | TAILQ_INIT(&cq)do { (&cq)->tqh_first = ((void *)0); (&cq)->tqh_last = &(&cq)->tqh_first; } while (0); |
| 356 | |
| 357 | for (;;) { |
| 358 | bus_dmamap_sync(dma->dma_tag, dma->dma_map, 0, dma->dma_size,(*(dma->dma_tag)->_dmamap_sync)((dma->dma_tag), (dma ->dma_map), (0), (dma->dma_size), (0x02 | 0x08)) |
| 359 | BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE)(*(dma->dma_tag)->_dmamap_sync)((dma->dma_tag), (dma ->dma_map), (0), (dma->dma_size), (0x02 | 0x08)); |
| 360 | |
| 361 | for (cons = sc->sc_xr_cons; cons != xr->xr_cons; cons++) { |
| 362 | desc = cons & (sc->sc_xr_ndesc - 1); |
| 363 | xbf_complete_cmd(sc, &cq, desc); |
| 364 | } |
| 365 | |
| 366 | sc->sc_xr_cons = cons; |
| 367 | |
| 368 | if (TAILQ_EMPTY(&cq)(((&cq)->tqh_first) == ((void *)0))) |
| 369 | break; |
| 370 | |
| 371 | s = splbio()splraise(0x6); |
| 372 | KERNEL_LOCK()_kernel_lock(); |
| 373 | TAILQ_FOREACH_SAFE(ccb, &cq, ccb_link, nccb)for ((ccb) = ((&cq)->tqh_first); (ccb) != ((void *)0) && ((nccb) = ((ccb)->ccb_link.tqe_next), 1); (ccb) = (nccb)) { |
| 374 | TAILQ_REMOVE(&cq, ccb, ccb_link)do { if (((ccb)->ccb_link.tqe_next) != ((void *)0)) (ccb)-> ccb_link.tqe_next->ccb_link.tqe_prev = (ccb)->ccb_link. tqe_prev; else (&cq)->tqh_last = (ccb)->ccb_link.tqe_prev ; *(ccb)->ccb_link.tqe_prev = (ccb)->ccb_link.tqe_next; ((ccb)->ccb_link.tqe_prev) = ((void *)-1); ((ccb)->ccb_link .tqe_next) = ((void *)-1); } while (0); |
| 375 | xbf_reclaim_cmd(ccb->ccb_xfer); |
| 376 | scsi_done(ccb->ccb_xfer); |
| 377 | } |
| 378 | KERNEL_UNLOCK()_kernel_unlock(); |
| 379 | splx(s)spllower(s); |
| 380 | } |
| 381 | } |
| 382 | |
| 383 | void |
| 384 | xbf_scsi_cmd(struct scsi_xfer *xs) |
| 385 | { |
| 386 | struct xbf_softc *sc = xs->sc_link->bus->sb_adapter_softc; |
| 387 | |
| 388 | switch (xs->cmd.opcode) { |
| 389 | case READ_COMMAND0x08: |
| 390 | case READ_100x28: |
| 391 | case READ_120xa8: |
| 392 | case READ_160x88: |
| 393 | case WRITE_COMMAND0x0a: |
| 394 | case WRITE_100x2a: |
| 395 | case WRITE_120xaa: |
| 396 | case WRITE_160x8a: |
| 397 | if (sc->sc_state != XBF_CONNECTED4) { |
| 398 | xbf_scsi_done(xs, XS_SELTIMEOUT3); |
| 399 | return; |
| 400 | } |
| 401 | break; |
| 402 | case SYNCHRONIZE_CACHE0x35: |
| 403 | if (!(sc->sc_caps & (XBF_CAP_BARRIER0x0001|XBF_CAP_FLUSH0x0002))) { |
| 404 | xbf_scsi_done(xs, XS_NOERROR0); |
| 405 | return; |
| 406 | } |
| 407 | break; |
| 408 | case INQUIRY0x12: |
| 409 | xbf_scsi_inq(xs); |
| 410 | return; |
| 411 | case READ_CAPACITY0x25: |
| 412 | xbf_scsi_capacity(xs); |
| 413 | return; |
| 414 | case READ_CAPACITY_160x9e: |
| 415 | xbf_scsi_capacity16(xs); |
| 416 | return; |
| 417 | case TEST_UNIT_READY0x00: |
| 418 | case START_STOP0x1b: |
| 419 | case PREVENT_ALLOW0x1e: |
| 420 | xbf_scsi_done(xs, XS_NOERROR0); |
| 421 | return; |
| 422 | default: |
| 423 | printf("%s cmd 0x%02x\n", __func__, xs->cmd.opcode); |
| 424 | case MODE_SENSE0x1a: |
| 425 | case MODE_SENSE_BIG0x5a: |
| 426 | case REPORT_LUNS0xa0: |
| 427 | case READ_TOC0x43: |
| 428 | xbf_scsi_done(xs, XS_DRIVER_STUFFUP2); |
| 429 | return; |
| 430 | } |
| 431 | |
| 432 | if (xbf_submit_cmd(xs)) { |
| 433 | xbf_scsi_done(xs, XS_DRIVER_STUFFUP2); |
| 434 | return; |
| 435 | } |
| 436 | |
| 437 | if (ISSET(xs->flags, SCSI_POLL)((xs->flags) & (0x00002)) && xbf_poll_cmd(xs)) { |
| 438 | printf("%s: op %#x timed out\n", sc->sc_dev.dv_xname, |
| 439 | xs->cmd.opcode); |
| 440 | if (sc->sc_state == XBF_CONNECTED4) { |
| 441 | xbf_reclaim_cmd(xs); |
| 442 | xbf_scsi_done(xs, XS_TIMEOUT4); |
| 443 | } |
| 444 | return; |
| 445 | } |
| 446 | } |
| 447 | |
| 448 | int |
| 449 | xbf_load_cmd(struct scsi_xfer *xs) |
| 450 | { |
| 451 | struct xbf_softc *sc = xs->sc_link->bus->sb_adapter_softc; |
| 452 | struct xbf_ccb *ccb = xs->io; |
| 453 | struct xbf_sge *sge; |
| 454 | union xbf_ring_desc *xrd; |
| 455 | bus_dmamap_t map; |
| 456 | int error, mapflags, nsg, seg; |
| 457 | int desc, ndesc = 0; |
| 458 | |
| 459 | map = ccb->ccb_dmap; |
| 460 | |
| 461 | mapflags = (sc->sc_domid << 16); |
| 462 | if (ISSET(xs->flags, SCSI_NOSLEEP)((xs->flags) & (0x00001))) |
| 463 | mapflags |= BUS_DMA_NOWAIT0x0001; |
| 464 | else |
| 465 | mapflags |= BUS_DMA_WAITOK0x0000; |
| 466 | if (ISSET(xs->flags, SCSI_DATA_IN)((xs->flags) & (0x00800))) |
| 467 | mapflags |= BUS_DMA_READ0x0200; |
| 468 | else |
| 469 | mapflags |= BUS_DMA_WRITE0x0400; |
| 470 | |
| 471 | error = bus_dmamap_load(sc->sc_dmat, map, xs->data, xs->datalen,(*(sc->sc_dmat)->_dmamap_load)((sc->sc_dmat), (map), (xs->data), (xs->datalen), (((void *)0)), (mapflags)) |
| 472 | NULL, mapflags)(*(sc->sc_dmat)->_dmamap_load)((sc->sc_dmat), (map), (xs->data), (xs->datalen), (((void *)0)), (mapflags)); |
| 473 | if (error) { |
| 474 | printf("%s: failed to load %d bytes of data\n", |
| 475 | sc->sc_dev.dv_xname, xs->datalen); |
| 476 | return (error); |
| 477 | } |
| 478 | |
| 479 | xrd = &sc->sc_xr->xr_desc[ccb->ccb_first]; |
| 480 | /* seg is the segment map iterator, nsg is the s-g list iterator */ |
| 481 | for (seg = 0, nsg = 0; seg < map->dm_nsegs; seg++, nsg++) { |
| 482 | if (nsg == XBF_MAX_SGE11) { |
| 483 | /* Number of segments so far */ |
| 484 | xrd->xrd_req.req_nsegs = nsg; |
| 485 | /* Pick next descriptor */ |
| 486 | ndesc++; |
| 487 | desc = (sc->sc_xr_prod + ndesc) & (sc->sc_xr_ndesc - 1); |
| 488 | xrd = &sc->sc_xr->xr_desc[desc]; |
| 489 | nsg = 0; |
| 490 | } |
| 491 | sge = &xrd->xrd_req.req_sgl[nsg]; |
| 492 | sge->sge_ref = map->dm_segs[seg].ds_addr; |
| 493 | sge->sge_first = nsg > 0 ? 0 : |
| 494 | (((vaddr_t)xs->data + ndesc * sc->sc_xrd_nblk * |
| 495 | (1 << XBF_SEC_SHIFT9)) & PAGE_MASK((1 << 12) - 1)) >> XBF_SEC_SHIFT9; |
| 496 | sge->sge_last = sge->sge_first + |
| 497 | (map->dm_segs[seg].ds_len >> XBF_SEC_SHIFT9) - 1; |
| 498 | |
| 499 | DPRINTF("%s: seg %d/%d ref %lu len %lu first %u last %u\n", |
| 500 | sc->sc_dev.dv_xname, nsg + 1, map->dm_nsegs, |
| 501 | map->dm_segs[seg].ds_addr, map->dm_segs[seg].ds_len, |
| 502 | sge->sge_first, sge->sge_last); |
| 503 | |
| 504 | KASSERT(sge->sge_last <= 7)((sge->sge_last <= 7) ? (void)0 : __assert("diagnostic " , "/usr/src/sys/dev/pv/xbf.c", 504, "sge->sge_last <= 7" )); |
| 505 | } |
| 506 | |
| 507 | xrd->xrd_req.req_nsegs = nsg; |
| 508 | |
| 509 | return (0); |
| 510 | } |
| 511 | |
| 512 | int |
| 513 | xbf_bounce_cmd(struct scsi_xfer *xs) |
| 514 | { |
| 515 | struct xbf_softc *sc = xs->sc_link->bus->sb_adapter_softc; |
| 516 | struct xbf_ccb *ccb = xs->io; |
| 517 | struct xbf_sge *sge; |
| 518 | struct xbf_dma_mem *dma; |
| 519 | union xbf_ring_desc *xrd; |
| 520 | bus_dmamap_t map; |
| 521 | bus_size_t size; |
| 522 | int error, mapflags, nsg, seg; |
| 523 | int desc, ndesc = 0; |
| 524 | |
| 525 | size = roundup(xs->datalen, PAGE_SIZE)((((xs->datalen)+(((1 << 12))-1))/((1 << 12))) *((1 << 12))); |
| 526 | if (size > MAXPHYS(64 * 1024)) |
| 527 | return (EFBIG27); |
| 528 | |
| 529 | mapflags = (sc->sc_domid << 16); |
| 530 | if (ISSET(xs->flags, SCSI_NOSLEEP)((xs->flags) & (0x00001))) |
| 531 | mapflags |= BUS_DMA_NOWAIT0x0001; |
| 532 | else |
| 533 | mapflags |= BUS_DMA_WAITOK0x0000; |
| 534 | if (ISSET(xs->flags, SCSI_DATA_IN)((xs->flags) & (0x00800))) |
| 535 | mapflags |= BUS_DMA_READ0x0200; |
| 536 | else |
| 537 | mapflags |= BUS_DMA_WRITE0x0400; |
| 538 | |
| 539 | dma = &ccb->ccb_bbuf; |
| 540 | error = xbf_dma_alloc(sc, dma, size, size / PAGE_SIZE(1 << 12), mapflags); |
| 541 | if (error) { |
| 542 | DPRINTF("%s: failed to allocate a %lu byte bounce buffer\n", |
| 543 | sc->sc_dev.dv_xname, size); |
| 544 | return (error); |
| 545 | } |
| 546 | |
| 547 | map = dma->dma_map; |
| 548 | |
| 549 | DPRINTF("%s: bouncing %d bytes via %lu size map with %d segments\n", |
| 550 | sc->sc_dev.dv_xname, xs->datalen, size, map->dm_nsegs); |
| 551 | |
| 552 | if (ISSET(xs->flags, SCSI_DATA_OUT)((xs->flags) & (0x01000))) |
| 553 | memcpy(dma->dma_vaddr, xs->data, xs->datalen)__builtin_memcpy((dma->dma_vaddr), (xs->data), (xs-> datalen)); |
| 554 | |
| 555 | xrd = &sc->sc_xr->xr_desc[ccb->ccb_first]; |
| 556 | /* seg is the map segment iterator, nsg is the s-g element iterator */ |
| 557 | for (seg = 0, nsg = 0; seg < map->dm_nsegs; seg++, nsg++) { |
| 558 | if (nsg == XBF_MAX_SGE11) { |
| 559 | /* Number of segments so far */ |
| 560 | xrd->xrd_req.req_nsegs = nsg; |
| 561 | /* Pick next descriptor */ |
| 562 | ndesc++; |
| 563 | desc = (sc->sc_xr_prod + ndesc) & (sc->sc_xr_ndesc - 1); |
| 564 | xrd = &sc->sc_xr->xr_desc[desc]; |
| 565 | nsg = 0; |
| 566 | } |
| 567 | sge = &xrd->xrd_req.req_sgl[nsg]; |
| 568 | sge->sge_ref = map->dm_segs[seg].ds_addr; |
| 569 | sge->sge_first = nsg > 0 ? 0 : |
| 570 | (((vaddr_t)dma->dma_vaddr + ndesc * sc->sc_xrd_nblk * |
| 571 | (1 << XBF_SEC_SHIFT9)) & PAGE_MASK((1 << 12) - 1)) >> XBF_SEC_SHIFT9; |
| 572 | sge->sge_last = sge->sge_first + |
| 573 | (map->dm_segs[seg].ds_len >> XBF_SEC_SHIFT9) - 1; |
| 574 | |
| 575 | DPRINTF("%s: seg %d/%d ref %lu len %lu first %u last %u\n", |
| 576 | sc->sc_dev.dv_xname, nsg + 1, map->dm_nsegs, |
| 577 | map->dm_segs[seg].ds_addr, map->dm_segs[seg].ds_len, |
| 578 | sge->sge_first, sge->sge_last); |
| 579 | |
| 580 | KASSERT(sge->sge_last <= 7)((sge->sge_last <= 7) ? (void)0 : __assert("diagnostic " , "/usr/src/sys/dev/pv/xbf.c", 580, "sge->sge_last <= 7" )); |
| 581 | } |
| 582 | |
| 583 | xrd->xrd_req.req_nsegs = nsg; |
| 584 | |
| 585 | return (0); |
| 586 | } |
| 587 | |
| 588 | void |
| 589 | xbf_reclaim_cmd(struct scsi_xfer *xs) |
| 590 | { |
| 591 | struct xbf_softc *sc = xs->sc_link->bus->sb_adapter_softc; |
| 592 | struct xbf_ccb *ccb = xs->io; |
| 593 | struct xbf_dma_mem *dma = &ccb->ccb_bbuf; |
| 594 | |
| 595 | if (dma->dma_size == 0) |
| 596 | return; |
| 597 | |
| 598 | if (ISSET(xs->flags, SCSI_DATA_IN)((xs->flags) & (0x00800))) |
| 599 | memcpy(xs->data, (caddr_t)dma->dma_vaddr, xs->datalen)__builtin_memcpy((xs->data), ((caddr_t)dma->dma_vaddr), (xs->datalen)); |
| 600 | |
| 601 | xbf_dma_free(sc, &ccb->ccb_bbuf); |
| 602 | } |
| 603 | |
| 604 | int |
| 605 | xbf_submit_cmd(struct scsi_xfer *xs) |
| 606 | { |
| 607 | struct xbf_softc *sc = xs->sc_link->bus->sb_adapter_softc; |
| 608 | struct xbf_ccb *ccb = xs->io; |
| 609 | union xbf_ring_desc *xrd; |
| 610 | struct scsi_rw *rw; |
| 611 | struct scsi_rw_10 *rw10; |
| 612 | struct scsi_rw_12 *rw12; |
| 613 | struct scsi_rw_16 *rw16; |
| 614 | uint64_t lba = 0; |
| 615 | uint32_t nblk = 0; |
| 616 | uint8_t operation = 0; |
| 617 | unsigned int ndesc = 0; |
| 618 | int desc, error; |
| 619 | |
| 620 | switch (xs->cmd.opcode) { |
| 621 | case READ_COMMAND0x08: |
| 622 | case READ_100x28: |
| 623 | case READ_120xa8: |
| 624 | case READ_160x88: |
| 625 | operation = XBF_OP_READ0; |
| 626 | break; |
| 627 | |
| 628 | case WRITE_COMMAND0x0a: |
| 629 | case WRITE_100x2a: |
| 630 | case WRITE_120xaa: |
| 631 | case WRITE_160x8a: |
| 632 | operation = XBF_OP_WRITE1; |
| 633 | break; |
| 634 | |
| 635 | case SYNCHRONIZE_CACHE0x35: |
| 636 | if (sc->sc_caps & XBF_CAP_FLUSH0x0002) |
| 637 | operation = XBF_OP_FLUSH3; |
| 638 | else if (sc->sc_caps & XBF_CAP_BARRIER0x0001) |
| 639 | operation = XBF_OP_BARRIER2; |
| 640 | break; |
| 641 | } |
| 642 | |
| 643 | /* |
| 644 | * READ/WRITE/SYNCHRONIZE commands. SYNCHRONIZE CACHE |
| 645 | * has the same layout as 10-byte READ/WRITE commands. |
| 646 | */ |
| 647 | if (xs->cmdlen == 6) { |
| 648 | rw = (struct scsi_rw *)&xs->cmd; |
| 649 | lba = _3btol(rw->addr) & (SRW_TOPADDR0x1F << 16 | 0xffff); |
| 650 | nblk = rw->length ? rw->length : 0x100; |
| 651 | } else if (xs->cmdlen == 10) { |
| 652 | rw10 = (struct scsi_rw_10 *)&xs->cmd; |
| 653 | lba = _4btol(rw10->addr); |
| 654 | nblk = _2btol(rw10->length); |
| 655 | } else if (xs->cmdlen == 12) { |
| 656 | rw12 = (struct scsi_rw_12 *)&xs->cmd; |
| 657 | lba = _4btol(rw12->addr); |
| 658 | nblk = _4btol(rw12->length); |
| 659 | } else if (xs->cmdlen == 16) { |
| 660 | rw16 = (struct scsi_rw_16 *)&xs->cmd; |
| 661 | lba = _8btol(rw16->addr); |
| 662 | nblk = _4btol(rw16->length); |
| 663 | } |
| 664 | |
| 665 | ccb->ccb_want = ccb->ccb_seen = 0; |
| 666 | |
| 667 | do { |
| 668 | desc = (sc->sc_xr_prod + ndesc) & (sc->sc_xr_ndesc - 1); |
| 669 | if (ndesc == 0) |
| 670 | ccb->ccb_first = desc; |
| 671 | |
| 672 | xrd = &sc->sc_xr->xr_desc[desc]; |
| 673 | xrd->xrd_req.req_op = operation; |
| 674 | xrd->xrd_req.req_unit = (uint16_t)sc->sc_unit; |
| 675 | xrd->xrd_req.req_sector = lba + ndesc * sc->sc_xrd_nblk; |
| 676 | |
| 677 | ccb->ccb_want |= 1 << ndesc; |
| 678 | ndesc++; |
| 679 | } while (ndesc * sc->sc_xrd_nblk < nblk); |
| 680 | |
| 681 | ccb->ccb_last = desc; |
| 682 | |
| 683 | if (operation == XBF_OP_READ0 || operation == XBF_OP_WRITE1) { |
| 684 | DPRINTF("%s: desc %u,%u %s%s lba %llu nsec %u " |
| 685 | "len %d\n", sc->sc_dev.dv_xname, ccb->ccb_first, |
| 686 | ccb->ccb_last, operation == XBF_OP_READ ? "read" : |
| 687 | "write", ISSET(xs->flags, SCSI_POLL) ? "-poll" : "", |
| 688 | lba, nblk, xs->datalen); |
| 689 | |
| 690 | if (((vaddr_t)xs->data & ((1 << XBF_SEC_SHIFT9) - 1)) == 0) |
| 691 | error = xbf_load_cmd(xs); |
| 692 | else |
| 693 | error = xbf_bounce_cmd(xs); |
| 694 | if (error) |
| 695 | return (-1); |
| 696 | } else { |
| 697 | DPRINTF("%s: desc %u %s%s lba %llu\n", sc->sc_dev.dv_xname, |
| 698 | ccb->ccb_first, operation == XBF_OP_FLUSH ? "flush" : |
| 699 | "barrier", ISSET(xs->flags, SCSI_POLL) ? "-poll" : "", |
| 700 | lba); |
| 701 | xrd->xrd_req.req_nsegs = 0; |
| 702 | } |
| 703 | |
| 704 | ccb->ccb_xfer = xs; |
| 705 | |
| 706 | bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmap, 0,(*(sc->sc_dmat)->_dmamap_sync)((sc->sc_dmat), (ccb-> ccb_dmap), (0), (ccb->ccb_dmap->dm_mapsize), (0x01 | 0x04 )) |
| 707 | ccb->ccb_dmap->dm_mapsize, BUS_DMASYNC_PREREAD |(*(sc->sc_dmat)->_dmamap_sync)((sc->sc_dmat), (ccb-> ccb_dmap), (0), (ccb->ccb_dmap->dm_mapsize), (0x01 | 0x04 )) |
| 708 | BUS_DMASYNC_PREWRITE)(*(sc->sc_dmat)->_dmamap_sync)((sc->sc_dmat), (ccb-> ccb_dmap), (0), (ccb->ccb_dmap->dm_mapsize), (0x01 | 0x04 )); |
| 709 | |
| 710 | mtx_enter(&sc->sc_ccb_sqlck); |
| 711 | TAILQ_INSERT_TAIL(&sc->sc_ccb_sq, ccb, ccb_link)do { (ccb)->ccb_link.tqe_next = ((void *)0); (ccb)->ccb_link .tqe_prev = (&sc->sc_ccb_sq)->tqh_last; *(&sc-> sc_ccb_sq)->tqh_last = (ccb); (&sc->sc_ccb_sq)-> tqh_last = &(ccb)->ccb_link.tqe_next; } while (0); |
| 712 | mtx_leave(&sc->sc_ccb_sqlck); |
| 713 | |
| 714 | sc->sc_xr_prod += ndesc; |
| 715 | sc->sc_xr->xr_prod = sc->sc_xr_prod; |
| 716 | sc->sc_xr->xr_cons_event = sc->sc_xr_prod; |
| 717 | |
| 718 | bus_dmamap_sync(sc->sc_dmat, sc->sc_xr_dma.dma_map, 0,(*(sc->sc_dmat)->_dmamap_sync)((sc->sc_dmat), (sc-> sc_xr_dma.dma_map), (0), (sc->sc_xr_dma.dma_map->dm_mapsize ), (0x01 | 0x04)) |
| 719 | sc->sc_xr_dma.dma_map->dm_mapsize, BUS_DMASYNC_PREREAD |(*(sc->sc_dmat)->_dmamap_sync)((sc->sc_dmat), (sc-> sc_xr_dma.dma_map), (0), (sc->sc_xr_dma.dma_map->dm_mapsize ), (0x01 | 0x04)) |
| 720 | BUS_DMASYNC_PREWRITE)(*(sc->sc_dmat)->_dmamap_sync)((sc->sc_dmat), (sc-> sc_xr_dma.dma_map), (0), (sc->sc_xr_dma.dma_map->dm_mapsize ), (0x01 | 0x04)); |
| 721 | |
| 722 | xen_intr_signal(sc->sc_xih); |
| 723 | |
| 724 | return (0); |
| 725 | } |
| 726 | |
| 727 | int |
| 728 | xbf_poll_cmd(struct scsi_xfer *xs) |
| 729 | { |
| 730 | int timo = 1000; |
| 731 | |
| 732 | do { |
| 733 | if (ISSET(xs->flags, ITSDONE)((xs->flags) & (0x00008))) |
| 734 | break; |
| 735 | if (ISSET(xs->flags, SCSI_NOSLEEP)((xs->flags) & (0x00001))) |
| 736 | delay(10)(*delay_func)(10); |
| 737 | else |
| 738 | tsleep_nsec(xs, PRIBIO16, "xbfpoll", USEC_TO_NSEC(10)); |
| 739 | xbf_intr(xs->sc_link->bus->sb_adapter_softc); |
| 740 | } while(--timo > 0); |
| 741 | |
| 742 | return (0); |
| 743 | } |
| 744 | |
| 745 | void |
| 746 | xbf_complete_cmd(struct xbf_softc *sc, struct xbf_ccb_queue *cq, int desc) |
| 747 | { |
| 748 | struct xbf_ccb *ccb; |
| 749 | union xbf_ring_desc *xrd; |
| 750 | bus_dmamap_t map; |
| 751 | uint32_t id, chunk; |
| 752 | int error; |
| 753 | |
| 754 | xrd = &sc->sc_xr->xr_desc[desc]; |
| 755 | error = xrd->xrd_rsp.rsp_status == XBF_OK0 ? XS_NOERROR0 : |
| 756 | XS_DRIVER_STUFFUP2; |
| 757 | |
| 758 | mtx_enter(&sc->sc_ccb_sqlck); |
| 759 | |
| 760 | /* |
| 761 | * To find a CCB for id equal to x within an interval [a, b] we must |
| 762 | * locate a CCB such that (x - a) mod N <= (b - a) mod N, where a is |
| 763 | * the first descriptor, b is the last one and N is the ring size. |
| 764 | */ |
| 765 | id = (uint32_t)xrd->xrd_rsp.rsp_id; |
| 766 | TAILQ_FOREACH(ccb, &sc->sc_ccb_sq, ccb_link)for((ccb) = ((&sc->sc_ccb_sq)->tqh_first); (ccb) != ((void *)0); (ccb) = ((ccb)->ccb_link.tqe_next)) { |
| 767 | if (((id - ccb->ccb_first) & (sc->sc_xr_ndesc - 1)) <= |
| 768 | ((ccb->ccb_last - ccb->ccb_first) & (sc->sc_xr_ndesc - 1))) |
| 769 | break; |
| 770 | } |
| 771 | KASSERT(ccb != NULL)((ccb != ((void *)0)) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/dev/pv/xbf.c" , 771, "ccb != NULL")); |
| 772 | |
| 773 | /* Assert that this chunk belongs to this CCB */ |
| 774 | chunk = 1 << ((id - ccb->ccb_first) & (sc->sc_xr_ndesc - 1)); |
| 775 | KASSERT((ccb->ccb_want & chunk) != 0)(((ccb->ccb_want & chunk) != 0) ? (void)0 : __assert("diagnostic " , "/usr/src/sys/dev/pv/xbf.c", 775, "(ccb->ccb_want & chunk) != 0" )); |
| 776 | KASSERT((ccb->ccb_seen & chunk) == 0)(((ccb->ccb_seen & chunk) == 0) ? (void)0 : __assert("diagnostic " , "/usr/src/sys/dev/pv/xbf.c", 776, "(ccb->ccb_seen & chunk) == 0" )); |
| 777 | |
| 778 | /* When all chunks are collected remove the CCB from the queue */ |
| 779 | ccb->ccb_seen |= chunk; |
| 780 | if (ccb->ccb_seen == ccb->ccb_want) |
| 781 | TAILQ_REMOVE(&sc->sc_ccb_sq, ccb, ccb_link)do { if (((ccb)->ccb_link.tqe_next) != ((void *)0)) (ccb)-> ccb_link.tqe_next->ccb_link.tqe_prev = (ccb)->ccb_link. tqe_prev; else (&sc->sc_ccb_sq)->tqh_last = (ccb)-> ccb_link.tqe_prev; *(ccb)->ccb_link.tqe_prev = (ccb)->ccb_link .tqe_next; ((ccb)->ccb_link.tqe_prev) = ((void *)-1); ((ccb )->ccb_link.tqe_next) = ((void *)-1); } while (0); |
| 782 | |
| 783 | mtx_leave(&sc->sc_ccb_sqlck); |
| 784 | |
| 785 | DPRINTF("%s: completing desc %d(%llu) op %u with error %d\n", |
| 786 | sc->sc_dev.dv_xname, desc, xrd->xrd_rsp.rsp_id, |
| 787 | xrd->xrd_rsp.rsp_op, xrd->xrd_rsp.rsp_status); |
| 788 | |
| 789 | memset(xrd, 0, sizeof(*xrd))__builtin_memset((xrd), (0), (sizeof(*xrd))); |
| 790 | xrd->xrd_req.req_id = desc; |
| 791 | |
| 792 | if (ccb->ccb_seen != ccb->ccb_want) |
| 793 | return; |
| 794 | |
| 795 | if (ccb->ccb_bbuf.dma_size > 0) |
| 796 | map = ccb->ccb_bbuf.dma_map; |
| 797 | else |
| 798 | map = ccb->ccb_dmap; |
| 799 | |
| 800 | bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,(*(sc->sc_dmat)->_dmamap_sync)((sc->sc_dmat), (map), (0), (map->dm_mapsize), (0x02 | 0x08)) |
| 801 | BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE)(*(sc->sc_dmat)->_dmamap_sync)((sc->sc_dmat), (map), (0), (map->dm_mapsize), (0x02 | 0x08)); |
| 802 | bus_dmamap_unload(sc->sc_dmat, map)(*(sc->sc_dmat)->_dmamap_unload)((sc->sc_dmat), (map )); |
| 803 | |
| 804 | ccb->ccb_xfer->resid = 0; |
| 805 | ccb->ccb_xfer->error = error; |
| 806 | TAILQ_INSERT_TAIL(cq, ccb, ccb_link)do { (ccb)->ccb_link.tqe_next = ((void *)0); (ccb)->ccb_link .tqe_prev = (cq)->tqh_last; *(cq)->tqh_last = (ccb); (cq )->tqh_last = &(ccb)->ccb_link.tqe_next; } while (0 ); |
| 807 | } |
| 808 | |
| 809 | void |
| 810 | xbf_scsi_inq(struct scsi_xfer *xs) |
| 811 | { |
| 812 | struct scsi_inquiry *inq = (struct scsi_inquiry *)&xs->cmd; |
| 813 | |
| 814 | if (ISSET(inq->flags, SI_EVPD)((inq->flags) & (0x01))) |
| 815 | xbf_scsi_done(xs, XS_DRIVER_STUFFUP2); |
| 816 | else |
| 817 | xbf_scsi_inquiry(xs); |
| 818 | } |
| 819 | |
| 820 | void |
| 821 | xbf_scsi_inquiry(struct scsi_xfer *xs) |
| 822 | { |
| 823 | struct xbf_softc *sc = xs->sc_link->bus->sb_adapter_softc; |
| 824 | struct scsi_inquiry_data inq; |
| 825 | |
| 826 | bzero(&inq, sizeof(inq))__builtin_bzero((&inq), (sizeof(inq))); |
| 827 | |
| 828 | switch (sc->sc_type) { |
| 829 | case XBF_CDROM1: |
| 830 | inq.device = T_CDROM0x05; |
| 831 | break; |
| 832 | default: |
| 833 | inq.device = T_DIRECT0x00; |
| 834 | break; |
| 835 | } |
| 836 | |
| 837 | inq.version = SCSI_REV_SPC30x05; |
| 838 | inq.response_format = SID_SCSI2_RESPONSE0x02; |
| 839 | inq.additional_length = SID_SCSI2_ALEN31; |
| 840 | inq.flags |= SID_CmdQue0x02; |
| 841 | bcopy("Xen ", inq.vendor, sizeof(inq.vendor)); |
| 842 | bcopy(sc->sc_prod, inq.product, sizeof(inq.product)); |
| 843 | bcopy("0000", inq.revision, sizeof(inq.revision)); |
| 844 | |
| 845 | scsi_copy_internal_data(xs, &inq, sizeof(inq)); |
| 846 | |
| 847 | xbf_scsi_done(xs, XS_NOERROR0); |
| 848 | } |
| 849 | |
| 850 | void |
| 851 | xbf_scsi_capacity(struct scsi_xfer *xs) |
| 852 | { |
| 853 | struct xbf_softc *sc = xs->sc_link->bus->sb_adapter_softc; |
| 854 | struct scsi_read_cap_data rcd; |
| 855 | uint64_t capacity; |
| 856 | |
| 857 | bzero(&rcd, sizeof(rcd))__builtin_bzero((&rcd), (sizeof(rcd))); |
| 858 | |
| 859 | capacity = sc->sc_disk_size - 1; |
| 860 | if (capacity > 0xffffffff) |
| 861 | capacity = 0xffffffff; |
| 862 | |
| 863 | _lto4b(capacity, rcd.addr); |
| 864 | _lto4b(sc->sc_block_size, rcd.length); |
| 865 | |
| 866 | bcopy(&rcd, xs->data, MIN(sizeof(rcd), xs->datalen)(((sizeof(rcd))<(xs->datalen))?(sizeof(rcd)):(xs->datalen ))); |
| 867 | |
| 868 | xbf_scsi_done(xs, XS_NOERROR0); |
| 869 | } |
| 870 | |
| 871 | void |
| 872 | xbf_scsi_capacity16(struct scsi_xfer *xs) |
| 873 | { |
| 874 | struct xbf_softc *sc = xs->sc_link->bus->sb_adapter_softc; |
| 875 | struct scsi_read_cap_data_16 rcd; |
| 876 | |
| 877 | bzero(&rcd, sizeof(rcd))__builtin_bzero((&rcd), (sizeof(rcd))); |
| 878 | |
| 879 | _lto8b(sc->sc_disk_size - 1, rcd.addr); |
| 880 | _lto4b(sc->sc_block_size, rcd.length); |
| 881 | |
| 882 | bcopy(&rcd, xs->data, MIN(sizeof(rcd), xs->datalen)(((sizeof(rcd))<(xs->datalen))?(sizeof(rcd)):(xs->datalen ))); |
| 883 | |
| 884 | xbf_scsi_done(xs, XS_NOERROR0); |
| 885 | } |
| 886 | |
| 887 | void |
| 888 | xbf_scsi_done(struct scsi_xfer *xs, int error) |
| 889 | { |
| 890 | int s; |
| 891 | |
| 892 | xs->error = error; |
| 893 | |
| 894 | s = splbio()splraise(0x6); |
| 895 | scsi_done(xs); |
| 896 | splx(s)spllower(s); |
| 897 | } |
| 898 | |
| 899 | int |
| 900 | xbf_get_type(struct xbf_softc *sc) |
| 901 | { |
| 902 | unsigned long long res; |
| 903 | const char *prop; |
| 904 | char val[32]; |
| 905 | int error; |
| 906 | |
| 907 | prop = "type"; |
| 908 | if ((error = xs_getprop(sc->sc_parent, sc->sc_backend, prop, val, |
| 909 | sizeof(val))) != 0) |
| 910 | goto errout; |
| 911 | snprintf(sc->sc_prod, sizeof(sc->sc_prod), "%s", val); |
| 912 | |
| 913 | prop = "dev"; |
| 914 | if ((error = xs_getprop(sc->sc_parent, sc->sc_backend, prop, val, |
| 915 | sizeof(val))) != 0) |
| 916 | goto errout; |
| 917 | snprintf(sc->sc_prod, sizeof(sc->sc_prod), "%s %s", sc->sc_prod, val); |
| 918 | |
| 919 | prop = "virtual-device"; |
| 920 | if ((error = xs_getnum(sc->sc_parent, sc->sc_node, prop, &res)) != 0) |
| 921 | goto errout; |
| 922 | sc->sc_unit = (uint32_t)res; |
| 923 | snprintf(sc->sc_prod, sizeof(sc->sc_prod), "%s %llu", sc->sc_prod, res); |
| 924 | |
| 925 | prop = "device-type"; |
| 926 | if ((error = xs_getprop(sc->sc_parent, sc->sc_node, prop, |
Although the value stored to 'error' is used in the enclosing expression, the value is never actually read from 'error' | |
| 927 | sc->sc_dtype, sizeof(sc->sc_dtype))) != 0) |
| 928 | goto errout; |
| 929 | if (!strcmp(sc->sc_dtype, "cdrom")) |
| 930 | sc->sc_type = XBF_CDROM1; |
| 931 | |
| 932 | return (0); |
| 933 | |
| 934 | errout: |
| 935 | printf("%s: failed to read \"%s\" property\n", sc->sc_dev.dv_xname, |
| 936 | prop); |
| 937 | return (-1); |
| 938 | } |
| 939 | |
| 940 | int |
| 941 | xbf_init(struct xbf_softc *sc) |
| 942 | { |
| 943 | unsigned long long res; |
| 944 | const char *action, *prop; |
| 945 | char pbuf[sizeof("ring-refXX")]; |
| 946 | unsigned int i; |
| 947 | int error; |
| 948 | |
| 949 | prop = "max-ring-page-order"; |
| 950 | error = xs_getnum(sc->sc_parent, sc->sc_backend, prop, &res); |
| 951 | if (error == 0) |
| 952 | sc->sc_xr_size = 1 << res; |
| 953 | if (error == ENOENT2) { |
| 954 | prop = "max-ring-pages"; |
| 955 | error = xs_getnum(sc->sc_parent, sc->sc_backend, prop, &res); |
| 956 | if (error == 0) |
| 957 | sc->sc_xr_size = res; |
| 958 | } |
| 959 | /* Fallback to the known minimum */ |
| 960 | if (error) |
| 961 | sc->sc_xr_size = XBF_MIN_RING_SIZE1; |
| 962 | |
| 963 | if (sc->sc_xr_size < XBF_MIN_RING_SIZE1) |
| 964 | sc->sc_xr_size = XBF_MIN_RING_SIZE1; |
| 965 | if (sc->sc_xr_size > XBF_MAX_RING_SIZE8) |
| 966 | sc->sc_xr_size = XBF_MAX_RING_SIZE8; |
| 967 | if (!powerof2(sc->sc_xr_size)((((sc->sc_xr_size)-1)&(sc->sc_xr_size))==0)) |
| 968 | sc->sc_xr_size = 1 << (fls(sc->sc_xr_size) - 1); |
| 969 | |
| 970 | sc->sc_xr_ndesc = ((sc->sc_xr_size * PAGE_SIZE(1 << 12)) - |
| 971 | sizeof(struct xbf_ring)) / sizeof(union xbf_ring_desc); |
| 972 | if (!powerof2(sc->sc_xr_ndesc)((((sc->sc_xr_ndesc)-1)&(sc->sc_xr_ndesc))==0)) |
| 973 | sc->sc_xr_ndesc = 1 << (fls(sc->sc_xr_ndesc) - 1); |
| 974 | if (sc->sc_xr_ndesc > XBF_MAX_REQS256) |
| 975 | sc->sc_xr_ndesc = XBF_MAX_REQS256; |
| 976 | |
| 977 | DPRINTF("%s: %u ring pages, %d requests\n", |
| 978 | sc->sc_dev.dv_xname, sc->sc_xr_size, sc->sc_xr_ndesc); |
| 979 | |
| 980 | if (xbf_ring_create(sc)) |
| 981 | return (-1); |
| 982 | |
| 983 | action = "set"; |
| 984 | |
| 985 | for (i = 0; i < sc->sc_xr_size; i++) { |
| 986 | if (i == 0 && sc->sc_xr_size == 1) |
| 987 | snprintf(pbuf, sizeof(pbuf), "ring-ref"); |
| 988 | else |
| 989 | snprintf(pbuf, sizeof(pbuf), "ring-ref%d", i); |
| 990 | prop = pbuf; |
| 991 | if (xs_setnum(sc->sc_parent, sc->sc_node, prop, |
| 992 | sc->sc_xr_ref[i])) |
| 993 | goto errout; |
| 994 | } |
| 995 | |
| 996 | if (sc->sc_xr_size > 1) { |
| 997 | prop = "num-ring-pages"; |
| 998 | if (xs_setnum(sc->sc_parent, sc->sc_node, prop, |
| 999 | sc->sc_xr_size)) |
| 1000 | goto errout; |
| 1001 | prop = "ring-page-order"; |
| 1002 | if (xs_setnum(sc->sc_parent, sc->sc_node, prop, |
| 1003 | fls(sc->sc_xr_size) - 1)) |
| 1004 | goto errout; |
| 1005 | } |
| 1006 | |
| 1007 | prop = "event-channel"; |
| 1008 | if (xs_setnum(sc->sc_parent, sc->sc_node, prop, sc->sc_xih)) |
| 1009 | goto errout; |
| 1010 | |
| 1011 | prop = "protocol"; |
| 1012 | #ifdef __amd64__1 |
| 1013 | if (xs_setprop(sc->sc_parent, sc->sc_node, prop, "x86_64-abi", |
| 1014 | strlen("x86_64-abi"))) |
| 1015 | goto errout; |
| 1016 | #else |
| 1017 | if (xs_setprop(sc->sc_parent, sc->sc_node, prop, "x86_32-abi", |
| 1018 | strlen("x86_32-abi"))) |
| 1019 | goto errout; |
| 1020 | #endif |
| 1021 | |
| 1022 | if (xs_setprop(sc->sc_parent, sc->sc_node, "state", |
| 1023 | XEN_STATE_INITIALIZED"3", strlen(XEN_STATE_INITIALIZED"3"))) { |
| 1024 | printf("%s: failed to set state to INITIALIZED\n", |
| 1025 | sc->sc_dev.dv_xname); |
| 1026 | xbf_ring_destroy(sc); |
| 1027 | return (-1); |
| 1028 | } |
| 1029 | |
| 1030 | if (xs_await_transition(sc->sc_parent, sc->sc_backend, "state", |
| 1031 | XEN_STATE_CONNECTED"4", 10000)) { |
| 1032 | printf("%s: timed out waiting for backend to connect\n", |
| 1033 | sc->sc_dev.dv_xname); |
| 1034 | xbf_ring_destroy(sc); |
| 1035 | return (-1); |
| 1036 | } |
| 1037 | |
| 1038 | action = "read"; |
| 1039 | |
| 1040 | prop = "sectors"; |
| 1041 | if ((error = xs_getnum(sc->sc_parent, sc->sc_backend, prop, &res)) != 0) |
| 1042 | goto errout; |
| 1043 | sc->sc_disk_size = res; |
| 1044 | |
| 1045 | prop = "sector-size"; |
| 1046 | if ((error = xs_getnum(sc->sc_parent, sc->sc_backend, prop, &res)) != 0) |
| 1047 | goto errout; |
| 1048 | sc->sc_block_size = res; |
| 1049 | |
| 1050 | prop = "feature-barrier"; |
| 1051 | if ((error = xs_getnum(sc->sc_parent, sc->sc_backend, prop, &res)) != 0 |
| 1052 | && error != ENOENT2) |
| 1053 | goto errout; |
| 1054 | if (error == 0 && res == 1) |
| 1055 | sc->sc_caps |= XBF_CAP_BARRIER0x0001; |
| 1056 | |
| 1057 | prop = "feature-flush-cache"; |
| 1058 | if ((error = xs_getnum(sc->sc_parent, sc->sc_backend, prop, &res)) != 0 |
| 1059 | && error != ENOENT2) |
| 1060 | goto errout; |
| 1061 | if (error == 0 && res == 1) |
| 1062 | sc->sc_caps |= XBF_CAP_FLUSH0x0002; |
| 1063 | |
| 1064 | #ifdef XBF_DEBUG |
| 1065 | if (sc->sc_caps) { |
| 1066 | printf("%s: features:", sc->sc_dev.dv_xname); |
| 1067 | if (sc->sc_caps & XBF_CAP_BARRIER0x0001) |
| 1068 | printf(" BARRIER"); |
| 1069 | if (sc->sc_caps & XBF_CAP_FLUSH0x0002) |
| 1070 | printf(" FLUSH"); |
| 1071 | printf("\n"); |
| 1072 | } |
| 1073 | #endif |
| 1074 | |
| 1075 | if (xs_setprop(sc->sc_parent, sc->sc_node, "state", |
| 1076 | XEN_STATE_CONNECTED"4", strlen(XEN_STATE_CONNECTED"4"))) { |
| 1077 | printf("%s: failed to set state to CONNECTED\n", |
| 1078 | sc->sc_dev.dv_xname); |
| 1079 | return (-1); |
| 1080 | } |
| 1081 | |
| 1082 | sc->sc_state = XBF_CONNECTED4; |
| 1083 | |
| 1084 | return (0); |
| 1085 | |
| 1086 | errout: |
| 1087 | printf("%s: failed to %s \"%s\" property (%d)\n", sc->sc_dev.dv_xname, |
| 1088 | action, prop, error); |
| 1089 | xbf_ring_destroy(sc); |
| 1090 | return (-1); |
| 1091 | } |
| 1092 | |
| 1093 | int |
| 1094 | xbf_dma_alloc(struct xbf_softc *sc, struct xbf_dma_mem *dma, |
| 1095 | bus_size_t size, int nsegs, int mapflags) |
| 1096 | { |
| 1097 | int error; |
| 1098 | |
| 1099 | dma->dma_tag = sc->sc_dmat; |
| 1100 | |
| 1101 | dma->dma_seg = mallocarray(nsegs, sizeof(bus_dma_segment_t), M_DEVBUF2, |
| 1102 | M_ZERO0x0008 | M_NOWAIT0x0002); |
| 1103 | if (dma->dma_seg == NULL((void *)0)) { |
| 1104 | printf("%s: failed to allocate a segment array\n", |
| 1105 | sc->sc_dev.dv_xname); |
| 1106 | return (ENOMEM12); |
| 1107 | } |
| 1108 | |
| 1109 | error = bus_dmamap_create(dma->dma_tag, size, nsegs, PAGE_SIZE, 0,(*(dma->dma_tag)->_dmamap_create)((dma->dma_tag), (size ), (nsegs), ((1 << 12)), (0), (0x0001), (&dma->dma_map )) |
| 1110 | BUS_DMA_NOWAIT, &dma->dma_map)(*(dma->dma_tag)->_dmamap_create)((dma->dma_tag), (size ), (nsegs), ((1 << 12)), (0), (0x0001), (&dma->dma_map )); |
| 1111 | if (error) { |
| 1112 | printf("%s: failed to create a memory map (%d)\n", |
| 1113 | sc->sc_dev.dv_xname, error); |
| 1114 | goto errout; |
| 1115 | } |
| 1116 | |
| 1117 | error = bus_dmamem_alloc(dma->dma_tag, size, PAGE_SIZE, 0,(*(dma->dma_tag)->_dmamem_alloc)((dma->dma_tag), (size ), ((1 << 12)), (0), (dma->dma_seg), (nsegs), (& dma->dma_rsegs), (0x1000 | 0x0001)) |
| 1118 | dma->dma_seg, nsegs, &dma->dma_rsegs, BUS_DMA_ZERO |(*(dma->dma_tag)->_dmamem_alloc)((dma->dma_tag), (size ), ((1 << 12)), (0), (dma->dma_seg), (nsegs), (& dma->dma_rsegs), (0x1000 | 0x0001)) |
| 1119 | BUS_DMA_NOWAIT)(*(dma->dma_tag)->_dmamem_alloc)((dma->dma_tag), (size ), ((1 << 12)), (0), (dma->dma_seg), (nsegs), (& dma->dma_rsegs), (0x1000 | 0x0001)); |
| 1120 | if (error) { |
| 1121 | printf("%s: failed to allocate DMA memory (%d)\n", |
| 1122 | sc->sc_dev.dv_xname, error); |
| 1123 | goto destroy; |
| 1124 | } |
| 1125 | |
| 1126 | error = bus_dmamem_map(dma->dma_tag, dma->dma_seg, dma->dma_rsegs,(*(dma->dma_tag)->_dmamem_map)((dma->dma_tag), (dma-> dma_seg), (dma->dma_rsegs), (size), (&dma->dma_vaddr ), (0x0001)) |
| 1127 | size, &dma->dma_vaddr, BUS_DMA_NOWAIT)(*(dma->dma_tag)->_dmamem_map)((dma->dma_tag), (dma-> dma_seg), (dma->dma_rsegs), (size), (&dma->dma_vaddr ), (0x0001)); |
| 1128 | if (error) { |
| 1129 | printf("%s: failed to map DMA memory (%d)\n", |
| 1130 | sc->sc_dev.dv_xname, error); |
| 1131 | goto free; |
| 1132 | } |
| 1133 | |
| 1134 | error = bus_dmamap_load(dma->dma_tag, dma->dma_map, dma->dma_vaddr,(*(dma->dma_tag)->_dmamap_load)((dma->dma_tag), (dma ->dma_map), (dma->dma_vaddr), (size), (((void *)0)), (mapflags | 0x0001)) |
| 1135 | size, NULL, mapflags | BUS_DMA_NOWAIT)(*(dma->dma_tag)->_dmamap_load)((dma->dma_tag), (dma ->dma_map), (dma->dma_vaddr), (size), (((void *)0)), (mapflags | 0x0001)); |
| 1136 | if (error) { |
| 1137 | printf("%s: failed to load DMA memory (%d)\n", |
| 1138 | sc->sc_dev.dv_xname, error); |
| 1139 | goto unmap; |
| 1140 | } |
| 1141 | |
| 1142 | dma->dma_size = size; |
| 1143 | dma->dma_nsegs = nsegs; |
| 1144 | return (0); |
| 1145 | |
| 1146 | unmap: |
| 1147 | bus_dmamem_unmap(dma->dma_tag, dma->dma_vaddr, size)(*(dma->dma_tag)->_dmamem_unmap)((dma->dma_tag), (dma ->dma_vaddr), (size)); |
| 1148 | free: |
| 1149 | bus_dmamem_free(dma->dma_tag, dma->dma_seg, dma->dma_rsegs)(*(dma->dma_tag)->_dmamem_free)((dma->dma_tag), (dma ->dma_seg), (dma->dma_rsegs)); |
| 1150 | destroy: |
| 1151 | bus_dmamap_destroy(dma->dma_tag, dma->dma_map)(*(dma->dma_tag)->_dmamap_destroy)((dma->dma_tag), ( dma->dma_map)); |
| 1152 | errout: |
| 1153 | free(dma->dma_seg, M_DEVBUF2, nsegs * sizeof(bus_dma_segment_t)); |
| 1154 | dma->dma_map = NULL((void *)0); |
| 1155 | dma->dma_tag = NULL((void *)0); |
| 1156 | return (error); |
| 1157 | } |
| 1158 | |
| 1159 | void |
| 1160 | xbf_dma_free(struct xbf_softc *sc, struct xbf_dma_mem *dma) |
| 1161 | { |
| 1162 | if (dma->dma_tag == NULL((void *)0) || dma->dma_map == NULL((void *)0)) |
| 1163 | return; |
| 1164 | bus_dmamap_sync(dma->dma_tag, dma->dma_map, 0, dma->dma_size,(*(dma->dma_tag)->_dmamap_sync)((dma->dma_tag), (dma ->dma_map), (0), (dma->dma_size), (0x02 | 0x08)) |
| 1165 | BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE)(*(dma->dma_tag)->_dmamap_sync)((dma->dma_tag), (dma ->dma_map), (0), (dma->dma_size), (0x02 | 0x08)); |
| 1166 | bus_dmamap_unload(dma->dma_tag, dma->dma_map)(*(dma->dma_tag)->_dmamap_unload)((dma->dma_tag), (dma ->dma_map)); |
| 1167 | bus_dmamem_unmap(dma->dma_tag, dma->dma_vaddr, dma->dma_size)(*(dma->dma_tag)->_dmamem_unmap)((dma->dma_tag), (dma ->dma_vaddr), (dma->dma_size)); |
| 1168 | bus_dmamem_free(dma->dma_tag, dma->dma_seg, dma->dma_rsegs)(*(dma->dma_tag)->_dmamem_free)((dma->dma_tag), (dma ->dma_seg), (dma->dma_rsegs)); |
| 1169 | bus_dmamap_destroy(dma->dma_tag, dma->dma_map)(*(dma->dma_tag)->_dmamap_destroy)((dma->dma_tag), ( dma->dma_map)); |
| 1170 | free(dma->dma_seg, M_DEVBUF2, dma->dma_nsegs * sizeof(bus_dma_segment_t)); |
| 1171 | dma->dma_seg = NULL((void *)0); |
| 1172 | dma->dma_map = NULL((void *)0); |
| 1173 | dma->dma_size = 0; |
| 1174 | } |
| 1175 | |
| 1176 | int |
| 1177 | xbf_ring_create(struct xbf_softc *sc) |
| 1178 | { |
| 1179 | int i; |
| 1180 | |
| 1181 | if (xbf_dma_alloc(sc, &sc->sc_xr_dma, sc->sc_xr_size * PAGE_SIZE(1 << 12), |
| 1182 | sc->sc_xr_size, sc->sc_domid << 16)) |
| 1183 | return (-1); |
| 1184 | for (i = 0; i < sc->sc_xr_dma.dma_map->dm_nsegs; i++) |
| 1185 | sc->sc_xr_ref[i] = sc->sc_xr_dma.dma_map->dm_segs[i].ds_addr; |
| 1186 | |
| 1187 | sc->sc_xr = (struct xbf_ring *)sc->sc_xr_dma.dma_vaddr; |
| 1188 | |
| 1189 | sc->sc_xr->xr_prod_event = sc->sc_xr->xr_cons_event = 1; |
| 1190 | |
| 1191 | for (i = 0; i < sc->sc_xr_ndesc; i++) |
| 1192 | sc->sc_xr->xr_desc[i].xrd_req.req_id = i; |
| 1193 | |
| 1194 | /* The number of contiguous blocks addressable by one descriptor */ |
| 1195 | sc->sc_xrd_nblk = (PAGE_SIZE(1 << 12) * XBF_MAX_SGE11) / (1 << XBF_SEC_SHIFT9); |
| 1196 | |
| 1197 | if (xbf_alloc_ccbs(sc)) { |
| 1198 | xbf_ring_destroy(sc); |
| 1199 | return (-1); |
| 1200 | } |
| 1201 | |
| 1202 | return (0); |
| 1203 | } |
| 1204 | |
| 1205 | void |
| 1206 | xbf_ring_destroy(struct xbf_softc *sc) |
| 1207 | { |
| 1208 | xbf_free_ccbs(sc); |
| 1209 | xbf_dma_free(sc, &sc->sc_xr_dma); |
| 1210 | sc->sc_xr = NULL((void *)0); |
| 1211 | } |
| 1212 | |
| 1213 | void |
| 1214 | xbf_stop(struct xbf_softc *sc) |
| 1215 | { |
| 1216 | struct xbf_ccb *ccb, *nccb; |
| 1217 | bus_dmamap_t map; |
| 1218 | |
| 1219 | bus_dmamap_sync(sc->sc_dmat, sc->sc_xr_dma.dma_map, 0,(*(sc->sc_dmat)->_dmamap_sync)((sc->sc_dmat), (sc-> sc_xr_dma.dma_map), (0), (sc->sc_xr_dma.dma_map->dm_mapsize ), (0x02 | 0x08)) |
| 1220 | sc->sc_xr_dma.dma_map->dm_mapsize, BUS_DMASYNC_POSTREAD |(*(sc->sc_dmat)->_dmamap_sync)((sc->sc_dmat), (sc-> sc_xr_dma.dma_map), (0), (sc->sc_xr_dma.dma_map->dm_mapsize ), (0x02 | 0x08)) |
| 1221 | BUS_DMASYNC_POSTWRITE)(*(sc->sc_dmat)->_dmamap_sync)((sc->sc_dmat), (sc-> sc_xr_dma.dma_map), (0), (sc->sc_xr_dma.dma_map->dm_mapsize ), (0x02 | 0x08)); |
| 1222 | |
| 1223 | TAILQ_FOREACH_SAFE(ccb, &sc->sc_ccb_sq, ccb_link, nccb)for ((ccb) = ((&sc->sc_ccb_sq)->tqh_first); (ccb) != ((void *)0) && ((nccb) = ((ccb)->ccb_link.tqe_next ), 1); (ccb) = (nccb)) { |
| 1224 | TAILQ_REMOVE(&sc->sc_ccb_sq, ccb, ccb_link)do { if (((ccb)->ccb_link.tqe_next) != ((void *)0)) (ccb)-> ccb_link.tqe_next->ccb_link.tqe_prev = (ccb)->ccb_link. tqe_prev; else (&sc->sc_ccb_sq)->tqh_last = (ccb)-> ccb_link.tqe_prev; *(ccb)->ccb_link.tqe_prev = (ccb)->ccb_link .tqe_next; ((ccb)->ccb_link.tqe_prev) = ((void *)-1); ((ccb )->ccb_link.tqe_next) = ((void *)-1); } while (0); |
| 1225 | |
| 1226 | if (ccb->ccb_bbuf.dma_size > 0) |
| 1227 | map = ccb->ccb_bbuf.dma_map; |
| 1228 | else |
| 1229 | map = ccb->ccb_dmap; |
| 1230 | bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,(*(sc->sc_dmat)->_dmamap_sync)((sc->sc_dmat), (map), (0), (map->dm_mapsize), (0x02 | 0x08)) |
| 1231 | BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE)(*(sc->sc_dmat)->_dmamap_sync)((sc->sc_dmat), (map), (0), (map->dm_mapsize), (0x02 | 0x08)); |
| 1232 | bus_dmamap_unload(sc->sc_dmat, map)(*(sc->sc_dmat)->_dmamap_unload)((sc->sc_dmat), (map )); |
| 1233 | |
| 1234 | xbf_reclaim_cmd(ccb->ccb_xfer); |
| 1235 | xbf_scsi_done(ccb->ccb_xfer, XS_SELTIMEOUT3); |
| 1236 | } |
| 1237 | |
| 1238 | xbf_ring_destroy(sc); |
| 1239 | } |
| 1240 | |
| 1241 | int |
| 1242 | xbf_alloc_ccbs(struct xbf_softc *sc) |
| 1243 | { |
| 1244 | int i, error; |
| 1245 | |
| 1246 | TAILQ_INIT(&sc->sc_ccb_fq)do { (&sc->sc_ccb_fq)->tqh_first = ((void *)0); (& sc->sc_ccb_fq)->tqh_last = &(&sc->sc_ccb_fq) ->tqh_first; } while (0); |
| 1247 | TAILQ_INIT(&sc->sc_ccb_sq)do { (&sc->sc_ccb_sq)->tqh_first = ((void *)0); (& sc->sc_ccb_sq)->tqh_last = &(&sc->sc_ccb_sq) ->tqh_first; } while (0); |
| 1248 | mtx_init(&sc->sc_ccb_fqlck, IPL_BIO)do { (void)(((void *)0)); (void)(0); __mtx_init((&sc-> sc_ccb_fqlck), ((((0x6)) > 0x0 && ((0x6)) < 0x9 ) ? 0x9 : ((0x6)))); } while (0); |
| 1249 | mtx_init(&sc->sc_ccb_sqlck, IPL_BIO)do { (void)(((void *)0)); (void)(0); __mtx_init((&sc-> sc_ccb_sqlck), ((((0x6)) > 0x0 && ((0x6)) < 0x9 ) ? 0x9 : ((0x6)))); } while (0); |
| 1250 | |
| 1251 | sc->sc_nccb = sc->sc_xr_ndesc / 2; |
| 1252 | |
| 1253 | sc->sc_ccbs = mallocarray(sc->sc_nccb, sizeof(struct xbf_ccb), |
| 1254 | M_DEVBUF2, M_ZERO0x0008 | M_NOWAIT0x0002); |
| 1255 | if (sc->sc_ccbs == NULL((void *)0)) { |
| 1256 | printf("%s: failed to allocate CCBs\n", sc->sc_dev.dv_xname); |
| 1257 | return (-1); |
| 1258 | } |
| 1259 | |
| 1260 | for (i = 0; i < sc->sc_nccb; i++) { |
| 1261 | /* |
| 1262 | * Each CCB is set up to use up to 2 descriptors and |
| 1263 | * each descriptor can transfer XBF_MAX_SGE number of |
| 1264 | * pages. |
| 1265 | */ |
| 1266 | error = bus_dmamap_create(sc->sc_dmat, MAXPHYS, 2 *(*(sc->sc_dmat)->_dmamap_create)((sc->sc_dmat), ((64 * 1024)), (2 * 11), ((1 << 12)), ((1 << 12)), (0x0001 ), (&sc->sc_ccbs[i].ccb_dmap)) |
| 1267 | XBF_MAX_SGE, PAGE_SIZE, PAGE_SIZE, BUS_DMA_NOWAIT,(*(sc->sc_dmat)->_dmamap_create)((sc->sc_dmat), ((64 * 1024)), (2 * 11), ((1 << 12)), ((1 << 12)), (0x0001 ), (&sc->sc_ccbs[i].ccb_dmap)) |
| 1268 | &sc->sc_ccbs[i].ccb_dmap)(*(sc->sc_dmat)->_dmamap_create)((sc->sc_dmat), ((64 * 1024)), (2 * 11), ((1 << 12)), ((1 << 12)), (0x0001 ), (&sc->sc_ccbs[i].ccb_dmap)); |
| 1269 | if (error) { |
| 1270 | printf("%s: failed to create a memory map for " |
| 1271 | "the xfer %d (%d)\n", sc->sc_dev.dv_xname, i, |
| 1272 | error); |
| 1273 | goto errout; |
| 1274 | } |
| 1275 | |
| 1276 | xbf_put_ccb(sc, &sc->sc_ccbs[i]); |
| 1277 | } |
| 1278 | |
| 1279 | scsi_iopool_init(&sc->sc_iopool, sc, xbf_get_ccb, xbf_put_ccb); |
| 1280 | |
| 1281 | return (0); |
| 1282 | |
| 1283 | errout: |
| 1284 | xbf_free_ccbs(sc); |
| 1285 | return (-1); |
| 1286 | } |
| 1287 | |
| 1288 | void |
| 1289 | xbf_free_ccbs(struct xbf_softc *sc) |
| 1290 | { |
| 1291 | struct xbf_ccb *ccb; |
| 1292 | int i; |
| 1293 | |
| 1294 | for (i = 0; i < sc->sc_nccb; i++) { |
| 1295 | ccb = &sc->sc_ccbs[i]; |
| 1296 | if (ccb->ccb_dmap == NULL((void *)0)) |
| 1297 | continue; |
| 1298 | bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmap, 0, 0,(*(sc->sc_dmat)->_dmamap_sync)((sc->sc_dmat), (ccb-> ccb_dmap), (0), (0), (0x02 | 0x08)) |
| 1299 | BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE)(*(sc->sc_dmat)->_dmamap_sync)((sc->sc_dmat), (ccb-> ccb_dmap), (0), (0), (0x02 | 0x08)); |
| 1300 | bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmap)(*(sc->sc_dmat)->_dmamap_unload)((sc->sc_dmat), (ccb ->ccb_dmap)); |
| 1301 | bus_dmamap_destroy(sc->sc_dmat, ccb->ccb_dmap)(*(sc->sc_dmat)->_dmamap_destroy)((sc->sc_dmat), (ccb ->ccb_dmap)); |
| 1302 | } |
| 1303 | |
| 1304 | free(sc->sc_ccbs, M_DEVBUF2, sc->sc_nccb * sizeof(struct xbf_ccb)); |
| 1305 | sc->sc_ccbs = NULL((void *)0); |
| 1306 | sc->sc_nccb = 0; |
| 1307 | } |
| 1308 | |
| 1309 | void * |
| 1310 | xbf_get_ccb(void *xsc) |
| 1311 | { |
| 1312 | struct xbf_softc *sc = xsc; |
| 1313 | struct xbf_ccb *ccb; |
| 1314 | |
| 1315 | if (sc->sc_state != XBF_CONNECTED4 && |
| 1316 | sc->sc_state != XBF_CLOSING5) |
| 1317 | return (NULL((void *)0)); |
| 1318 | |
| 1319 | mtx_enter(&sc->sc_ccb_fqlck); |
| 1320 | ccb = TAILQ_FIRST(&sc->sc_ccb_fq)((&sc->sc_ccb_fq)->tqh_first); |
| 1321 | if (ccb != NULL((void *)0)) |
| 1322 | TAILQ_REMOVE(&sc->sc_ccb_fq, ccb, ccb_link)do { if (((ccb)->ccb_link.tqe_next) != ((void *)0)) (ccb)-> ccb_link.tqe_next->ccb_link.tqe_prev = (ccb)->ccb_link. tqe_prev; else (&sc->sc_ccb_fq)->tqh_last = (ccb)-> ccb_link.tqe_prev; *(ccb)->ccb_link.tqe_prev = (ccb)->ccb_link .tqe_next; ((ccb)->ccb_link.tqe_prev) = ((void *)-1); ((ccb )->ccb_link.tqe_next) = ((void *)-1); } while (0); |
| 1323 | mtx_leave(&sc->sc_ccb_fqlck); |
| 1324 | |
| 1325 | return (ccb); |
| 1326 | } |
| 1327 | |
| 1328 | void |
| 1329 | xbf_put_ccb(void *xsc, void *io) |
| 1330 | { |
| 1331 | struct xbf_softc *sc = xsc; |
| 1332 | struct xbf_ccb *ccb = io; |
| 1333 | |
| 1334 | ccb->ccb_xfer = NULL((void *)0); |
| 1335 | |
| 1336 | mtx_enter(&sc->sc_ccb_fqlck); |
| 1337 | TAILQ_INSERT_HEAD(&sc->sc_ccb_fq, ccb, ccb_link)do { if (((ccb)->ccb_link.tqe_next = (&sc->sc_ccb_fq )->tqh_first) != ((void *)0)) (&sc->sc_ccb_fq)-> tqh_first->ccb_link.tqe_prev = &(ccb)->ccb_link.tqe_next ; else (&sc->sc_ccb_fq)->tqh_last = &(ccb)-> ccb_link.tqe_next; (&sc->sc_ccb_fq)->tqh_first = (ccb ); (ccb)->ccb_link.tqe_prev = &(&sc->sc_ccb_fq) ->tqh_first; } while (0); |
| 1338 | mtx_leave(&sc->sc_ccb_fqlck); |
| 1339 | } |