17b13bc96SSascha Wildner /*-
27b13bc96SSascha Wildner * Copyright (c) 2018 VMware, Inc.
37b13bc96SSascha Wildner *
47b13bc96SSascha Wildner * SPDX-License-Identifier: (BSD-2-Clause OR GPL-2.0)
57b13bc96SSascha Wildner */
67b13bc96SSascha Wildner
71c0b11abSSascha Wildner #include "opt_pvscsi.h"
87b13bc96SSascha Wildner
97b13bc96SSascha Wildner #include <sys/param.h>
107b13bc96SSascha Wildner #include <sys/bus.h>
117b13bc96SSascha Wildner #include <sys/errno.h>
127b13bc96SSascha Wildner #include <sys/kernel.h>
137b13bc96SSascha Wildner #include <sys/malloc.h>
147b13bc96SSascha Wildner #include <sys/module.h>
157b13bc96SSascha Wildner #include <sys/queue.h>
167b13bc96SSascha Wildner #include <sys/rman.h>
177b13bc96SSascha Wildner #include <sys/sysctl.h>
187b13bc96SSascha Wildner #include <sys/systm.h>
197b13bc96SSascha Wildner
201c0b11abSSascha Wildner #include <bus/pci/pcireg.h>
211c0b11abSSascha Wildner #include <bus/pci/pcivar.h>
227b13bc96SSascha Wildner
231c0b11abSSascha Wildner #include <bus/cam/cam.h>
241c0b11abSSascha Wildner #include <bus/cam/cam_ccb.h>
251c0b11abSSascha Wildner #include <bus/cam/cam_debug.h>
261c0b11abSSascha Wildner #include <bus/cam/cam_periph.h>
271c0b11abSSascha Wildner #include <bus/cam/cam_sim.h>
281c0b11abSSascha Wildner #include <bus/cam/cam_xpt_periph.h>
291c0b11abSSascha Wildner #include <bus/cam/cam_xpt_sim.h>
301c0b11abSSascha Wildner #include <bus/cam/scsi/scsi_message.h>
317b13bc96SSascha Wildner
327b13bc96SSascha Wildner #include "pvscsi.h"
337b13bc96SSascha Wildner
347b13bc96SSascha Wildner #define PVSCSI_DEFAULT_NUM_PAGES_REQ_RING 8
357b13bc96SSascha Wildner #define PVSCSI_SENSE_LENGTH 256
367b13bc96SSascha Wildner
377b13bc96SSascha Wildner MALLOC_DECLARE(M_PVSCSI);
387b13bc96SSascha Wildner MALLOC_DEFINE(M_PVSCSI, "pvscsi", "PVSCSI memory");
397b13bc96SSascha Wildner
407b13bc96SSascha Wildner #ifdef PVSCSI_DEBUG_LOGGING
417b13bc96SSascha Wildner #define DEBUG_PRINTF(level, dev, fmt, ...) \
427b13bc96SSascha Wildner do { \
437b13bc96SSascha Wildner if (pvscsi_log_level >= (level)) { \
447b13bc96SSascha Wildner device_printf((dev), (fmt), ##__VA_ARGS__); \
457b13bc96SSascha Wildner } \
467b13bc96SSascha Wildner } while(0)
477b13bc96SSascha Wildner #else
487b13bc96SSascha Wildner #define DEBUG_PRINTF(level, dev, fmt, ...)
497b13bc96SSascha Wildner #endif /* PVSCSI_DEBUG_LOGGING */
507b13bc96SSascha Wildner
517b13bc96SSascha Wildner #define ccb_pvscsi_hcb spriv_ptr0
527b13bc96SSascha Wildner #define ccb_pvscsi_sc spriv_ptr1
537b13bc96SSascha Wildner
547b13bc96SSascha Wildner struct pvscsi_softc;
557b13bc96SSascha Wildner struct pvscsi_hcb;
567b13bc96SSascha Wildner struct pvscsi_dma;
577b13bc96SSascha Wildner
587b13bc96SSascha Wildner static inline uint32_t pvscsi_reg_read(struct pvscsi_softc *sc,
597b13bc96SSascha Wildner uint32_t offset);
607b13bc96SSascha Wildner static inline void pvscsi_reg_write(struct pvscsi_softc *sc, uint32_t offset,
617b13bc96SSascha Wildner uint32_t val);
627b13bc96SSascha Wildner static inline uint32_t pvscsi_read_intr_status(struct pvscsi_softc *sc);
637b13bc96SSascha Wildner static inline void pvscsi_write_intr_status(struct pvscsi_softc *sc,
647b13bc96SSascha Wildner uint32_t val);
657b13bc96SSascha Wildner static inline void pvscsi_intr_enable(struct pvscsi_softc *sc);
667b13bc96SSascha Wildner static inline void pvscsi_intr_disable(struct pvscsi_softc *sc);
677b13bc96SSascha Wildner static void pvscsi_kick_io(struct pvscsi_softc *sc, uint8_t cdb0);
687b13bc96SSascha Wildner static void pvscsi_write_cmd(struct pvscsi_softc *sc, uint32_t cmd, void *data,
697b13bc96SSascha Wildner uint32_t len);
707b13bc96SSascha Wildner static uint32_t pvscsi_get_max_targets(struct pvscsi_softc *sc);
717b13bc96SSascha Wildner static int pvscsi_setup_req_call(struct pvscsi_softc *sc, uint32_t enable);
727b13bc96SSascha Wildner static void pvscsi_setup_rings(struct pvscsi_softc *sc);
737b13bc96SSascha Wildner static void pvscsi_setup_msg_ring(struct pvscsi_softc *sc);
747b13bc96SSascha Wildner static int pvscsi_hw_supports_msg(struct pvscsi_softc *sc);
757b13bc96SSascha Wildner
767b13bc96SSascha Wildner static void pvscsi_timeout(void *arg);
777b13bc96SSascha Wildner static void pvscsi_freeze(struct pvscsi_softc *sc);
787b13bc96SSascha Wildner static void pvscsi_adapter_reset(struct pvscsi_softc *sc);
797b13bc96SSascha Wildner static void pvscsi_bus_reset(struct pvscsi_softc *sc);
807b13bc96SSascha Wildner static void pvscsi_device_reset(struct pvscsi_softc *sc, uint32_t target);
817b13bc96SSascha Wildner static void pvscsi_abort(struct pvscsi_softc *sc, uint32_t target,
827b13bc96SSascha Wildner union ccb *ccb);
837b13bc96SSascha Wildner
847b13bc96SSascha Wildner static void pvscsi_process_completion(struct pvscsi_softc *sc,
857b13bc96SSascha Wildner struct pvscsi_ring_cmp_desc *e);
867b13bc96SSascha Wildner static void pvscsi_process_cmp_ring(struct pvscsi_softc *sc);
877b13bc96SSascha Wildner static void pvscsi_process_msg(struct pvscsi_softc *sc,
887b13bc96SSascha Wildner struct pvscsi_ring_msg_desc *e);
897b13bc96SSascha Wildner static void pvscsi_process_msg_ring(struct pvscsi_softc *sc);
901c0b11abSSascha Wildner static void pvscsi_rescan_callback(struct cam_periph *periph, union ccb *ccb);
917b13bc96SSascha Wildner
927b13bc96SSascha Wildner static void pvscsi_intr_locked(struct pvscsi_softc *sc);
937b13bc96SSascha Wildner static void pvscsi_intr(void *xsc);
947b13bc96SSascha Wildner static void pvscsi_poll(struct cam_sim *sim);
957b13bc96SSascha Wildner
967b13bc96SSascha Wildner static void pvscsi_execute_ccb(void *arg, bus_dma_segment_t *segs, int nseg,
977b13bc96SSascha Wildner int error);
987b13bc96SSascha Wildner static void pvscsi_action(struct cam_sim *sim, union ccb *ccb);
997b13bc96SSascha Wildner
1007b13bc96SSascha Wildner static inline uint64_t pvscsi_hcb_to_context(struct pvscsi_softc *sc,
1017b13bc96SSascha Wildner struct pvscsi_hcb *hcb);
1027b13bc96SSascha Wildner static inline struct pvscsi_hcb* pvscsi_context_to_hcb(struct pvscsi_softc *sc,
1037b13bc96SSascha Wildner uint64_t context);
1047b13bc96SSascha Wildner static struct pvscsi_hcb * pvscsi_hcb_get(struct pvscsi_softc *sc);
1057b13bc96SSascha Wildner static void pvscsi_hcb_put(struct pvscsi_softc *sc, struct pvscsi_hcb *hcb);
1067b13bc96SSascha Wildner
1077b13bc96SSascha Wildner static void pvscsi_dma_cb(void *arg, bus_dma_segment_t *segs, int nseg,
1087b13bc96SSascha Wildner int error);
1097b13bc96SSascha Wildner static void pvscsi_dma_free(struct pvscsi_softc *sc, struct pvscsi_dma *dma);
1107b13bc96SSascha Wildner static int pvscsi_dma_alloc(struct pvscsi_softc *sc, struct pvscsi_dma *dma,
1117b13bc96SSascha Wildner bus_size_t size, bus_size_t alignment);
1127b13bc96SSascha Wildner static int pvscsi_dma_alloc_ppns(struct pvscsi_softc *sc,
1137b13bc96SSascha Wildner struct pvscsi_dma *dma, uint64_t *ppn_list, uint32_t num_pages);
1147b13bc96SSascha Wildner static void pvscsi_dma_free_per_hcb(struct pvscsi_softc *sc,
1157b13bc96SSascha Wildner uint32_t hcbs_allocated);
1167b13bc96SSascha Wildner static int pvscsi_dma_alloc_per_hcb(struct pvscsi_softc *sc);
1177b13bc96SSascha Wildner static void pvscsi_free_rings(struct pvscsi_softc *sc);
1187b13bc96SSascha Wildner static int pvscsi_allocate_rings(struct pvscsi_softc *sc);
1197b13bc96SSascha Wildner static void pvscsi_free_interrupts(struct pvscsi_softc *sc);
1207b13bc96SSascha Wildner static int pvscsi_setup_interrupts(struct pvscsi_softc *sc);
1217b13bc96SSascha Wildner static void pvscsi_free_all(struct pvscsi_softc *sc);
1227b13bc96SSascha Wildner
1237b13bc96SSascha Wildner static int pvscsi_attach(device_t dev);
1247b13bc96SSascha Wildner static int pvscsi_detach(device_t dev);
1257b13bc96SSascha Wildner static int pvscsi_probe(device_t dev);
1267b13bc96SSascha Wildner static int pvscsi_shutdown(device_t dev);
1277b13bc96SSascha Wildner static int pvscsi_get_tunable(struct pvscsi_softc *sc, char *name, int value);
1287b13bc96SSascha Wildner
1297b13bc96SSascha Wildner #ifdef PVSCSI_DEBUG_LOGGING
1307b13bc96SSascha Wildner static int pvscsi_log_level = 0;
1311c0b11abSSascha Wildner static SYSCTL_NODE(_hw, OID_AUTO, pvscsi, CTLFLAG_RD, 0,
1327b13bc96SSascha Wildner "PVSCSI driver parameters");
1331c0b11abSSascha Wildner SYSCTL_INT(_hw_pvscsi, OID_AUTO, log_level, CTLFLAG_RW, &pvscsi_log_level,
1347b13bc96SSascha Wildner 0, "PVSCSI debug log level");
1351c0b11abSSascha Wildner TUNABLE_INT("hw.pvscsi.log_level", &pvscsi_log_level);
1367b13bc96SSascha Wildner #endif
1377b13bc96SSascha Wildner
1387b13bc96SSascha Wildner static int pvscsi_request_ring_pages = 0;
1397b13bc96SSascha Wildner TUNABLE_INT("hw.pvscsi.request_ring_pages", &pvscsi_request_ring_pages);
1407b13bc96SSascha Wildner
1417b13bc96SSascha Wildner static int pvscsi_use_msg = 1;
1427b13bc96SSascha Wildner TUNABLE_INT("hw.pvscsi.use_msg", &pvscsi_use_msg);
1437b13bc96SSascha Wildner
1447b13bc96SSascha Wildner static int pvscsi_use_msi = 1;
1457b13bc96SSascha Wildner TUNABLE_INT("hw.pvscsi.use_msi", &pvscsi_use_msi);
1467b13bc96SSascha Wildner
1471c0b11abSSascha Wildner #if 0 /* XXX swildner: MSI-X support */
1487b13bc96SSascha Wildner static int pvscsi_use_msix = 1;
1497b13bc96SSascha Wildner TUNABLE_INT("hw.pvscsi.use_msix", &pvscsi_use_msix);
1501c0b11abSSascha Wildner #endif
1517b13bc96SSascha Wildner
1527b13bc96SSascha Wildner static int pvscsi_use_req_call_threshold = 1;
1537b13bc96SSascha Wildner TUNABLE_INT("hw.pvscsi.use_req_call_threshold", &pvscsi_use_req_call_threshold);
1547b13bc96SSascha Wildner
1557b13bc96SSascha Wildner static int pvscsi_max_queue_depth = 0;
1567b13bc96SSascha Wildner TUNABLE_INT("hw.pvscsi.max_queue_depth", &pvscsi_max_queue_depth);
1577b13bc96SSascha Wildner
1587b13bc96SSascha Wildner struct pvscsi_sg_list {
1597b13bc96SSascha Wildner struct pvscsi_sg_element sge[PVSCSI_MAX_SG_ENTRIES_PER_SEGMENT];
1607b13bc96SSascha Wildner };
1617b13bc96SSascha Wildner
1627b13bc96SSascha Wildner #define PVSCSI_ABORT_TIMEOUT 2
1637b13bc96SSascha Wildner #define PVSCSI_RESET_TIMEOUT 10
1647b13bc96SSascha Wildner
1657b13bc96SSascha Wildner #define PVSCSI_HCB_NONE 0
1667b13bc96SSascha Wildner #define PVSCSI_HCB_ABORT 1
1677b13bc96SSascha Wildner #define PVSCSI_HCB_DEVICE_RESET 2
1687b13bc96SSascha Wildner #define PVSCSI_HCB_BUS_RESET 3
1697b13bc96SSascha Wildner
1707b13bc96SSascha Wildner struct pvscsi_hcb {
1717b13bc96SSascha Wildner union ccb *ccb;
1727b13bc96SSascha Wildner struct pvscsi_ring_req_desc *e;
1737b13bc96SSascha Wildner int recovery;
1747b13bc96SSascha Wildner SLIST_ENTRY(pvscsi_hcb) links;
1757b13bc96SSascha Wildner
1767b13bc96SSascha Wildner struct callout callout;
1777b13bc96SSascha Wildner bus_dmamap_t dma_map;
1787b13bc96SSascha Wildner void *sense_buffer;
1797b13bc96SSascha Wildner bus_addr_t sense_buffer_paddr;
1807b13bc96SSascha Wildner struct pvscsi_sg_list *sg_list;
1817b13bc96SSascha Wildner bus_addr_t sg_list_paddr;
1827b13bc96SSascha Wildner };
1837b13bc96SSascha Wildner
1847b13bc96SSascha Wildner struct pvscsi_dma
1857b13bc96SSascha Wildner {
1867b13bc96SSascha Wildner bus_dma_tag_t tag;
1877b13bc96SSascha Wildner bus_dmamap_t map;
1887b13bc96SSascha Wildner void *vaddr;
1897b13bc96SSascha Wildner bus_addr_t paddr;
1907b13bc96SSascha Wildner bus_size_t size;
1917b13bc96SSascha Wildner };
1927b13bc96SSascha Wildner
1937b13bc96SSascha Wildner struct pvscsi_softc {
1947b13bc96SSascha Wildner device_t dev;
1951c0b11abSSascha Wildner struct lock lock;
1967b13bc96SSascha Wildner struct cam_sim *sim;
1977b13bc96SSascha Wildner struct cam_path *bus_path;
1987b13bc96SSascha Wildner int frozen;
1997b13bc96SSascha Wildner struct pvscsi_rings_state *rings_state;
2007b13bc96SSascha Wildner struct pvscsi_ring_req_desc *req_ring;
2017b13bc96SSascha Wildner struct pvscsi_ring_cmp_desc *cmp_ring;
2027b13bc96SSascha Wildner struct pvscsi_ring_msg_desc *msg_ring;
2037b13bc96SSascha Wildner uint32_t hcb_cnt;
2047b13bc96SSascha Wildner struct pvscsi_hcb *hcbs;
2057b13bc96SSascha Wildner SLIST_HEAD(, pvscsi_hcb) free_list;
2067b13bc96SSascha Wildner bus_dma_tag_t parent_dmat;
2077b13bc96SSascha Wildner bus_dma_tag_t buffer_dmat;
2087b13bc96SSascha Wildner
2097b13bc96SSascha Wildner bool use_msg;
2107b13bc96SSascha Wildner uint32_t max_targets;
2117b13bc96SSascha Wildner int mm_rid;
2127b13bc96SSascha Wildner struct resource *mm_res;
2137b13bc96SSascha Wildner int irq_id;
2141c0b11abSSascha Wildner int irq_type;
2157b13bc96SSascha Wildner struct resource *irq_res;
2167b13bc96SSascha Wildner void *irq_handler;
2177b13bc96SSascha Wildner int use_req_call_threshold;
2187b13bc96SSascha Wildner int use_msi_or_msix;
2197b13bc96SSascha Wildner
2207b13bc96SSascha Wildner uint64_t rings_state_ppn;
2217b13bc96SSascha Wildner uint32_t req_ring_num_pages;
2227b13bc96SSascha Wildner uint64_t req_ring_ppn[PVSCSI_MAX_NUM_PAGES_REQ_RING];
2237b13bc96SSascha Wildner uint32_t cmp_ring_num_pages;
2247b13bc96SSascha Wildner uint64_t cmp_ring_ppn[PVSCSI_MAX_NUM_PAGES_CMP_RING];
2257b13bc96SSascha Wildner uint32_t msg_ring_num_pages;
2267b13bc96SSascha Wildner uint64_t msg_ring_ppn[PVSCSI_MAX_NUM_PAGES_MSG_RING];
2277b13bc96SSascha Wildner
2287b13bc96SSascha Wildner struct pvscsi_dma rings_state_dma;
2297b13bc96SSascha Wildner struct pvscsi_dma req_ring_dma;
2307b13bc96SSascha Wildner struct pvscsi_dma cmp_ring_dma;
2317b13bc96SSascha Wildner struct pvscsi_dma msg_ring_dma;
2327b13bc96SSascha Wildner
2337b13bc96SSascha Wildner struct pvscsi_dma sg_list_dma;
2347b13bc96SSascha Wildner struct pvscsi_dma sense_buffer_dma;
2357b13bc96SSascha Wildner };
2367b13bc96SSascha Wildner
pvscsi_get_tunable(struct pvscsi_softc * sc,char * name,int value)2377b13bc96SSascha Wildner static int pvscsi_get_tunable(struct pvscsi_softc *sc, char *name, int value)
2387b13bc96SSascha Wildner {
2397b13bc96SSascha Wildner char cfg[64];
2407b13bc96SSascha Wildner
2411c0b11abSSascha Wildner ksnprintf(cfg, sizeof(cfg), "hw.pvscsi.%d.%s", device_get_unit(sc->dev),
2427b13bc96SSascha Wildner name);
2437b13bc96SSascha Wildner TUNABLE_INT_FETCH(cfg, &value);
2447b13bc96SSascha Wildner
2457b13bc96SSascha Wildner return (value);
2467b13bc96SSascha Wildner }
2477b13bc96SSascha Wildner
2487b13bc96SSascha Wildner static void
pvscsi_freeze(struct pvscsi_softc * sc)2497b13bc96SSascha Wildner pvscsi_freeze(struct pvscsi_softc *sc)
2507b13bc96SSascha Wildner {
2517b13bc96SSascha Wildner
2527b13bc96SSascha Wildner if (!sc->frozen) {
2537b13bc96SSascha Wildner xpt_freeze_simq(sc->sim, 1);
2547b13bc96SSascha Wildner sc->frozen = 1;
2557b13bc96SSascha Wildner }
2567b13bc96SSascha Wildner }
2577b13bc96SSascha Wildner
2587b13bc96SSascha Wildner static inline uint32_t
pvscsi_reg_read(struct pvscsi_softc * sc,uint32_t offset)2597b13bc96SSascha Wildner pvscsi_reg_read(struct pvscsi_softc *sc, uint32_t offset)
2607b13bc96SSascha Wildner {
2617b13bc96SSascha Wildner
2627b13bc96SSascha Wildner return (bus_read_4(sc->mm_res, offset));
2637b13bc96SSascha Wildner }
2647b13bc96SSascha Wildner
2657b13bc96SSascha Wildner static inline void
pvscsi_reg_write(struct pvscsi_softc * sc,uint32_t offset,uint32_t val)2667b13bc96SSascha Wildner pvscsi_reg_write(struct pvscsi_softc *sc, uint32_t offset, uint32_t val)
2677b13bc96SSascha Wildner {
2687b13bc96SSascha Wildner
2697b13bc96SSascha Wildner bus_write_4(sc->mm_res, offset, val);
2707b13bc96SSascha Wildner }
2717b13bc96SSascha Wildner
2727b13bc96SSascha Wildner static inline uint32_t
pvscsi_read_intr_status(struct pvscsi_softc * sc)2737b13bc96SSascha Wildner pvscsi_read_intr_status(struct pvscsi_softc *sc)
2747b13bc96SSascha Wildner {
2757b13bc96SSascha Wildner
2767b13bc96SSascha Wildner return (pvscsi_reg_read(sc, PVSCSI_REG_OFFSET_INTR_STATUS));
2777b13bc96SSascha Wildner }
2787b13bc96SSascha Wildner
2797b13bc96SSascha Wildner static inline void
pvscsi_write_intr_status(struct pvscsi_softc * sc,uint32_t val)2807b13bc96SSascha Wildner pvscsi_write_intr_status(struct pvscsi_softc *sc, uint32_t val)
2817b13bc96SSascha Wildner {
2827b13bc96SSascha Wildner
2837b13bc96SSascha Wildner pvscsi_reg_write(sc, PVSCSI_REG_OFFSET_INTR_STATUS, val);
2847b13bc96SSascha Wildner }
2857b13bc96SSascha Wildner
2867b13bc96SSascha Wildner static inline void
pvscsi_intr_enable(struct pvscsi_softc * sc)2877b13bc96SSascha Wildner pvscsi_intr_enable(struct pvscsi_softc *sc)
2887b13bc96SSascha Wildner {
2897b13bc96SSascha Wildner uint32_t mask;
2907b13bc96SSascha Wildner
2917b13bc96SSascha Wildner mask = PVSCSI_INTR_CMPL_MASK;
2927b13bc96SSascha Wildner if (sc->use_msg) {
2937b13bc96SSascha Wildner mask |= PVSCSI_INTR_MSG_MASK;
2947b13bc96SSascha Wildner }
2957b13bc96SSascha Wildner
2967b13bc96SSascha Wildner pvscsi_reg_write(sc, PVSCSI_REG_OFFSET_INTR_MASK, mask);
2977b13bc96SSascha Wildner }
2987b13bc96SSascha Wildner
2997b13bc96SSascha Wildner static inline void
pvscsi_intr_disable(struct pvscsi_softc * sc)3007b13bc96SSascha Wildner pvscsi_intr_disable(struct pvscsi_softc *sc)
3017b13bc96SSascha Wildner {
3027b13bc96SSascha Wildner
3037b13bc96SSascha Wildner pvscsi_reg_write(sc, PVSCSI_REG_OFFSET_INTR_MASK, 0);
3047b13bc96SSascha Wildner }
3057b13bc96SSascha Wildner
3067b13bc96SSascha Wildner static void
pvscsi_kick_io(struct pvscsi_softc * sc,uint8_t cdb0)3077b13bc96SSascha Wildner pvscsi_kick_io(struct pvscsi_softc *sc, uint8_t cdb0)
3087b13bc96SSascha Wildner {
3097b13bc96SSascha Wildner struct pvscsi_rings_state *s;
3107b13bc96SSascha Wildner
3117b13bc96SSascha Wildner if (cdb0 == READ_6 || cdb0 == READ_10 ||
3127b13bc96SSascha Wildner cdb0 == READ_12 || cdb0 == READ_16 ||
3137b13bc96SSascha Wildner cdb0 == WRITE_6 || cdb0 == WRITE_10 ||
3147b13bc96SSascha Wildner cdb0 == WRITE_12 || cdb0 == WRITE_16) {
3157b13bc96SSascha Wildner s = sc->rings_state;
3167b13bc96SSascha Wildner
3177b13bc96SSascha Wildner if (!sc->use_req_call_threshold ||
3187b13bc96SSascha Wildner (s->req_prod_idx - s->req_cons_idx) >=
3197b13bc96SSascha Wildner s->req_call_threshold) {
3207b13bc96SSascha Wildner pvscsi_reg_write(sc, PVSCSI_REG_OFFSET_KICK_RW_IO, 0);
3217b13bc96SSascha Wildner }
3227b13bc96SSascha Wildner } else {
3237b13bc96SSascha Wildner pvscsi_reg_write(sc, PVSCSI_REG_OFFSET_KICK_NON_RW_IO, 0);
3247b13bc96SSascha Wildner }
3257b13bc96SSascha Wildner }
3267b13bc96SSascha Wildner
3277b13bc96SSascha Wildner static void
pvscsi_write_cmd(struct pvscsi_softc * sc,uint32_t cmd,void * data,uint32_t len)3287b13bc96SSascha Wildner pvscsi_write_cmd(struct pvscsi_softc *sc, uint32_t cmd, void *data,
3297b13bc96SSascha Wildner uint32_t len)
3307b13bc96SSascha Wildner {
3317b13bc96SSascha Wildner uint32_t *data_ptr;
3327b13bc96SSascha Wildner int i;
3337b13bc96SSascha Wildner
3347b13bc96SSascha Wildner KASSERT(len % sizeof(uint32_t) == 0,
3357b13bc96SSascha Wildner ("command size not a multiple of 4"));
3367b13bc96SSascha Wildner
3377b13bc96SSascha Wildner data_ptr = data;
3387b13bc96SSascha Wildner len /= sizeof(uint32_t);
3397b13bc96SSascha Wildner
3407b13bc96SSascha Wildner pvscsi_reg_write(sc, PVSCSI_REG_OFFSET_COMMAND, cmd);
3417b13bc96SSascha Wildner for (i = 0; i < len; ++i) {
3427b13bc96SSascha Wildner pvscsi_reg_write(sc, PVSCSI_REG_OFFSET_COMMAND_DATA,
3437b13bc96SSascha Wildner data_ptr[i]);
3447b13bc96SSascha Wildner }
3457b13bc96SSascha Wildner }
3467b13bc96SSascha Wildner
pvscsi_hcb_to_context(struct pvscsi_softc * sc,struct pvscsi_hcb * hcb)3477b13bc96SSascha Wildner static inline uint64_t pvscsi_hcb_to_context(struct pvscsi_softc *sc,
3487b13bc96SSascha Wildner struct pvscsi_hcb *hcb)
3497b13bc96SSascha Wildner {
3507b13bc96SSascha Wildner
3517b13bc96SSascha Wildner /* Offset by 1 because context must not be 0 */
3527b13bc96SSascha Wildner return (hcb - sc->hcbs + 1);
3537b13bc96SSascha Wildner }
3547b13bc96SSascha Wildner
pvscsi_context_to_hcb(struct pvscsi_softc * sc,uint64_t context)3557b13bc96SSascha Wildner static inline struct pvscsi_hcb* pvscsi_context_to_hcb(struct pvscsi_softc *sc,
3567b13bc96SSascha Wildner uint64_t context)
3577b13bc96SSascha Wildner {
3587b13bc96SSascha Wildner
3597b13bc96SSascha Wildner return (sc->hcbs + (context - 1));
3607b13bc96SSascha Wildner }
3617b13bc96SSascha Wildner
3627b13bc96SSascha Wildner static struct pvscsi_hcb *
pvscsi_hcb_get(struct pvscsi_softc * sc)3637b13bc96SSascha Wildner pvscsi_hcb_get(struct pvscsi_softc *sc)
3647b13bc96SSascha Wildner {
3657b13bc96SSascha Wildner struct pvscsi_hcb *hcb;
3667b13bc96SSascha Wildner
3671c0b11abSSascha Wildner KKASSERT(lockowned(&sc->lock));
3687b13bc96SSascha Wildner
3697b13bc96SSascha Wildner hcb = SLIST_FIRST(&sc->free_list);
3707b13bc96SSascha Wildner if (hcb) {
3717b13bc96SSascha Wildner SLIST_REMOVE_HEAD(&sc->free_list, links);
3727b13bc96SSascha Wildner }
3737b13bc96SSascha Wildner
3747b13bc96SSascha Wildner return (hcb);
3757b13bc96SSascha Wildner }
3767b13bc96SSascha Wildner
3777b13bc96SSascha Wildner static void
pvscsi_hcb_put(struct pvscsi_softc * sc,struct pvscsi_hcb * hcb)3787b13bc96SSascha Wildner pvscsi_hcb_put(struct pvscsi_softc *sc, struct pvscsi_hcb *hcb)
3797b13bc96SSascha Wildner {
3807b13bc96SSascha Wildner
3811c0b11abSSascha Wildner KKASSERT(lockowned(&sc->lock));
3827b13bc96SSascha Wildner hcb->ccb = NULL;
3837b13bc96SSascha Wildner hcb->e = NULL;
3847b13bc96SSascha Wildner hcb->recovery = PVSCSI_HCB_NONE;
3857b13bc96SSascha Wildner SLIST_INSERT_HEAD(&sc->free_list, hcb, links);
3867b13bc96SSascha Wildner }
3877b13bc96SSascha Wildner
3887b13bc96SSascha Wildner static uint32_t
pvscsi_get_max_targets(struct pvscsi_softc * sc)3897b13bc96SSascha Wildner pvscsi_get_max_targets(struct pvscsi_softc *sc)
3907b13bc96SSascha Wildner {
3917b13bc96SSascha Wildner uint32_t max_targets;
3927b13bc96SSascha Wildner
3937b13bc96SSascha Wildner pvscsi_write_cmd(sc, PVSCSI_CMD_GET_MAX_TARGETS, NULL, 0);
3947b13bc96SSascha Wildner
3957b13bc96SSascha Wildner max_targets = pvscsi_reg_read(sc, PVSCSI_REG_OFFSET_COMMAND_STATUS);
3967b13bc96SSascha Wildner
3977b13bc96SSascha Wildner if (max_targets == ~0) {
3987b13bc96SSascha Wildner max_targets = 16;
3997b13bc96SSascha Wildner }
4007b13bc96SSascha Wildner
4017b13bc96SSascha Wildner return (max_targets);
4027b13bc96SSascha Wildner }
4037b13bc96SSascha Wildner
pvscsi_setup_req_call(struct pvscsi_softc * sc,uint32_t enable)4047b13bc96SSascha Wildner static int pvscsi_setup_req_call(struct pvscsi_softc *sc, uint32_t enable)
4057b13bc96SSascha Wildner {
4067b13bc96SSascha Wildner uint32_t status;
4077b13bc96SSascha Wildner struct pvscsi_cmd_desc_setup_req_call cmd;
4087b13bc96SSascha Wildner
4097b13bc96SSascha Wildner if (!pvscsi_get_tunable(sc, "pvscsi_use_req_call_threshold",
4107b13bc96SSascha Wildner pvscsi_use_req_call_threshold)) {
4117b13bc96SSascha Wildner return (0);
4127b13bc96SSascha Wildner }
4137b13bc96SSascha Wildner
4147b13bc96SSascha Wildner pvscsi_reg_write(sc, PVSCSI_REG_OFFSET_COMMAND,
4157b13bc96SSascha Wildner PVSCSI_CMD_SETUP_REQCALLTHRESHOLD);
4167b13bc96SSascha Wildner status = pvscsi_reg_read(sc, PVSCSI_REG_OFFSET_COMMAND_STATUS);
4177b13bc96SSascha Wildner
4187b13bc96SSascha Wildner if (status != -1) {
4197b13bc96SSascha Wildner bzero(&cmd, sizeof(cmd));
4207b13bc96SSascha Wildner cmd.enable = enable;
4217b13bc96SSascha Wildner pvscsi_write_cmd(sc, PVSCSI_CMD_SETUP_REQCALLTHRESHOLD,
4227b13bc96SSascha Wildner &cmd, sizeof(cmd));
4237b13bc96SSascha Wildner status = pvscsi_reg_read(sc, PVSCSI_REG_OFFSET_COMMAND_STATUS);
4247b13bc96SSascha Wildner
4257b13bc96SSascha Wildner return (status != 0);
4267b13bc96SSascha Wildner } else {
4277b13bc96SSascha Wildner return (0);
4287b13bc96SSascha Wildner }
4297b13bc96SSascha Wildner }
4307b13bc96SSascha Wildner
4317b13bc96SSascha Wildner static void
pvscsi_dma_cb(void * arg,bus_dma_segment_t * segs,int nseg,int error)4327b13bc96SSascha Wildner pvscsi_dma_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
4337b13bc96SSascha Wildner {
4347b13bc96SSascha Wildner bus_addr_t *dest;
4357b13bc96SSascha Wildner
4367b13bc96SSascha Wildner KASSERT(nseg == 1, ("more than one segment"));
4377b13bc96SSascha Wildner
4387b13bc96SSascha Wildner dest = arg;
4397b13bc96SSascha Wildner
4407b13bc96SSascha Wildner if (!error) {
4417b13bc96SSascha Wildner *dest = segs->ds_addr;
4427b13bc96SSascha Wildner }
4437b13bc96SSascha Wildner }
4447b13bc96SSascha Wildner
4457b13bc96SSascha Wildner static void
pvscsi_dma_free(struct pvscsi_softc * sc,struct pvscsi_dma * dma)4467b13bc96SSascha Wildner pvscsi_dma_free(struct pvscsi_softc *sc, struct pvscsi_dma *dma)
4477b13bc96SSascha Wildner {
4487b13bc96SSascha Wildner
4497b13bc96SSascha Wildner if (dma->tag != NULL) {
4507b13bc96SSascha Wildner if (dma->paddr != 0) {
4517b13bc96SSascha Wildner bus_dmamap_unload(dma->tag, dma->map);
4527b13bc96SSascha Wildner }
4537b13bc96SSascha Wildner
4547b13bc96SSascha Wildner if (dma->vaddr != NULL) {
4557b13bc96SSascha Wildner bus_dmamem_free(dma->tag, dma->vaddr, dma->map);
4567b13bc96SSascha Wildner }
4577b13bc96SSascha Wildner
4587b13bc96SSascha Wildner bus_dma_tag_destroy(dma->tag);
4597b13bc96SSascha Wildner }
4607b13bc96SSascha Wildner
4617b13bc96SSascha Wildner bzero(dma, sizeof(*dma));
4627b13bc96SSascha Wildner }
4637b13bc96SSascha Wildner
4647b13bc96SSascha Wildner static int
pvscsi_dma_alloc(struct pvscsi_softc * sc,struct pvscsi_dma * dma,bus_size_t size,bus_size_t alignment)4657b13bc96SSascha Wildner pvscsi_dma_alloc(struct pvscsi_softc *sc, struct pvscsi_dma *dma,
4667b13bc96SSascha Wildner bus_size_t size, bus_size_t alignment)
4677b13bc96SSascha Wildner {
4687b13bc96SSascha Wildner int error;
4697b13bc96SSascha Wildner
4707b13bc96SSascha Wildner bzero(dma, sizeof(*dma));
4717b13bc96SSascha Wildner
4727b13bc96SSascha Wildner error = bus_dma_tag_create(sc->parent_dmat, alignment, 0,
473*030b0c8cSMichael Neumann BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, size, 1, size,
4741c0b11abSSascha Wildner BUS_DMA_ALLOCNOW, &dma->tag);
4757b13bc96SSascha Wildner if (error) {
4767b13bc96SSascha Wildner device_printf(sc->dev, "error creating dma tag, error %d\n",
4777b13bc96SSascha Wildner error);
4787b13bc96SSascha Wildner goto fail;
4797b13bc96SSascha Wildner }
4807b13bc96SSascha Wildner
4817b13bc96SSascha Wildner error = bus_dmamem_alloc(dma->tag, &dma->vaddr,
4827b13bc96SSascha Wildner BUS_DMA_NOWAIT | BUS_DMA_ZERO, &dma->map);
4837b13bc96SSascha Wildner if (error) {
4847b13bc96SSascha Wildner device_printf(sc->dev, "error allocating dma mem, error %d\n",
4857b13bc96SSascha Wildner error);
4867b13bc96SSascha Wildner goto fail;
4877b13bc96SSascha Wildner }
4887b13bc96SSascha Wildner
4897b13bc96SSascha Wildner error = bus_dmamap_load(dma->tag, dma->map, dma->vaddr, size,
4907b13bc96SSascha Wildner pvscsi_dma_cb, &dma->paddr, BUS_DMA_NOWAIT);
4917b13bc96SSascha Wildner if (error) {
4921c0b11abSSascha Wildner device_printf(sc->dev, "error mapping dma mem, error %d\n",
4937b13bc96SSascha Wildner error);
4947b13bc96SSascha Wildner goto fail;
4957b13bc96SSascha Wildner }
4967b13bc96SSascha Wildner
4977b13bc96SSascha Wildner dma->size = size;
4987b13bc96SSascha Wildner
4997b13bc96SSascha Wildner fail:
5007b13bc96SSascha Wildner if (error) {
5017b13bc96SSascha Wildner pvscsi_dma_free(sc, dma);
5027b13bc96SSascha Wildner }
5037b13bc96SSascha Wildner return (error);
5047b13bc96SSascha Wildner }
5057b13bc96SSascha Wildner
5067b13bc96SSascha Wildner static int
pvscsi_dma_alloc_ppns(struct pvscsi_softc * sc,struct pvscsi_dma * dma,uint64_t * ppn_list,uint32_t num_pages)5077b13bc96SSascha Wildner pvscsi_dma_alloc_ppns(struct pvscsi_softc *sc, struct pvscsi_dma *dma,
5087b13bc96SSascha Wildner uint64_t *ppn_list, uint32_t num_pages)
5097b13bc96SSascha Wildner {
5107b13bc96SSascha Wildner int error;
5117b13bc96SSascha Wildner uint32_t i;
5127b13bc96SSascha Wildner uint64_t ppn;
5137b13bc96SSascha Wildner
5147b13bc96SSascha Wildner error = pvscsi_dma_alloc(sc, dma, num_pages * PAGE_SIZE, PAGE_SIZE);
5157b13bc96SSascha Wildner if (error) {
5167b13bc96SSascha Wildner device_printf(sc->dev, "Error allocating pages, error %d\n",
5177b13bc96SSascha Wildner error);
5187b13bc96SSascha Wildner return (error);
5197b13bc96SSascha Wildner }
5207b13bc96SSascha Wildner
5217b13bc96SSascha Wildner ppn = dma->paddr >> PAGE_SHIFT;
5227b13bc96SSascha Wildner for (i = 0; i < num_pages; i++) {
5237b13bc96SSascha Wildner ppn_list[i] = ppn + i;
5247b13bc96SSascha Wildner }
5257b13bc96SSascha Wildner
5267b13bc96SSascha Wildner return (0);
5277b13bc96SSascha Wildner }
5287b13bc96SSascha Wildner
5297b13bc96SSascha Wildner static void
pvscsi_dma_free_per_hcb(struct pvscsi_softc * sc,uint32_t hcbs_allocated)5307b13bc96SSascha Wildner pvscsi_dma_free_per_hcb(struct pvscsi_softc *sc, uint32_t hcbs_allocated)
5317b13bc96SSascha Wildner {
5327b13bc96SSascha Wildner int i;
5337b13bc96SSascha Wildner int lock_owned;
5347b13bc96SSascha Wildner struct pvscsi_hcb *hcb;
5357b13bc96SSascha Wildner
5361c0b11abSSascha Wildner lock_owned = lockowned(&sc->lock);
5377b13bc96SSascha Wildner
5387b13bc96SSascha Wildner if (lock_owned) {
5391c0b11abSSascha Wildner lockmgr(&sc->lock, LK_RELEASE);
5407b13bc96SSascha Wildner }
5417b13bc96SSascha Wildner for (i = 0; i < hcbs_allocated; ++i) {
5427b13bc96SSascha Wildner hcb = sc->hcbs + i;
5437b13bc96SSascha Wildner callout_drain(&hcb->callout);
5447b13bc96SSascha Wildner };
5457b13bc96SSascha Wildner if (lock_owned) {
5461c0b11abSSascha Wildner lockmgr(&sc->lock, LK_EXCLUSIVE);
5477b13bc96SSascha Wildner }
5487b13bc96SSascha Wildner
5497b13bc96SSascha Wildner for (i = 0; i < hcbs_allocated; ++i) {
5507b13bc96SSascha Wildner hcb = sc->hcbs + i;
5517b13bc96SSascha Wildner bus_dmamap_destroy(sc->buffer_dmat, hcb->dma_map);
5527b13bc96SSascha Wildner };
5537b13bc96SSascha Wildner
5547b13bc96SSascha Wildner pvscsi_dma_free(sc, &sc->sense_buffer_dma);
5557b13bc96SSascha Wildner pvscsi_dma_free(sc, &sc->sg_list_dma);
5567b13bc96SSascha Wildner }
5577b13bc96SSascha Wildner
5587b13bc96SSascha Wildner static int
pvscsi_dma_alloc_per_hcb(struct pvscsi_softc * sc)5597b13bc96SSascha Wildner pvscsi_dma_alloc_per_hcb(struct pvscsi_softc *sc)
5607b13bc96SSascha Wildner {
5617b13bc96SSascha Wildner int i;
5627b13bc96SSascha Wildner int error;
5637b13bc96SSascha Wildner struct pvscsi_hcb *hcb;
5647b13bc96SSascha Wildner
5657b13bc96SSascha Wildner i = 0;
5667b13bc96SSascha Wildner
5677b13bc96SSascha Wildner error = pvscsi_dma_alloc(sc, &sc->sg_list_dma,
5687b13bc96SSascha Wildner sizeof(struct pvscsi_sg_list) * sc->hcb_cnt, 1);
5697b13bc96SSascha Wildner if (error) {
5707b13bc96SSascha Wildner device_printf(sc->dev,
5717b13bc96SSascha Wildner "Error allocation sg list DMA memory, error %d\n", error);
5727b13bc96SSascha Wildner goto fail;
5737b13bc96SSascha Wildner }
5747b13bc96SSascha Wildner
5757b13bc96SSascha Wildner error = pvscsi_dma_alloc(sc, &sc->sense_buffer_dma,
5767b13bc96SSascha Wildner PVSCSI_SENSE_LENGTH * sc->hcb_cnt, 1);
5777b13bc96SSascha Wildner if (error) {
5787b13bc96SSascha Wildner device_printf(sc->dev,
5797b13bc96SSascha Wildner "Error allocation sg list DMA memory, error %d\n", error);
5807b13bc96SSascha Wildner goto fail;
5817b13bc96SSascha Wildner }
5827b13bc96SSascha Wildner
5837b13bc96SSascha Wildner for (i = 0; i < sc->hcb_cnt; ++i) {
5847b13bc96SSascha Wildner hcb = sc->hcbs + i;
5857b13bc96SSascha Wildner
5867b13bc96SSascha Wildner error = bus_dmamap_create(sc->buffer_dmat, 0, &hcb->dma_map);
5877b13bc96SSascha Wildner if (error) {
5887b13bc96SSascha Wildner device_printf(sc->dev,
5897b13bc96SSascha Wildner "Error creating dma map for hcb %d, error %d\n",
5907b13bc96SSascha Wildner i, error);
5917b13bc96SSascha Wildner goto fail;
5927b13bc96SSascha Wildner }
5937b13bc96SSascha Wildner
5947b13bc96SSascha Wildner hcb->sense_buffer =
5957b13bc96SSascha Wildner (void *)((caddr_t)sc->sense_buffer_dma.vaddr +
5967b13bc96SSascha Wildner PVSCSI_SENSE_LENGTH * i);
5977b13bc96SSascha Wildner hcb->sense_buffer_paddr =
5987b13bc96SSascha Wildner sc->sense_buffer_dma.paddr + PVSCSI_SENSE_LENGTH * i;
5997b13bc96SSascha Wildner
6007b13bc96SSascha Wildner hcb->sg_list =
6017b13bc96SSascha Wildner (struct pvscsi_sg_list *)((caddr_t)sc->sg_list_dma.vaddr +
6027b13bc96SSascha Wildner sizeof(struct pvscsi_sg_list) * i);
6037b13bc96SSascha Wildner hcb->sg_list_paddr =
6047b13bc96SSascha Wildner sc->sg_list_dma.paddr + sizeof(struct pvscsi_sg_list) * i;
6057b13bc96SSascha Wildner
6061c0b11abSSascha Wildner callout_init_lk(&hcb->callout, &sc->lock);
6077b13bc96SSascha Wildner }
6087b13bc96SSascha Wildner
6097b13bc96SSascha Wildner SLIST_INIT(&sc->free_list);
6107b13bc96SSascha Wildner for (i = (sc->hcb_cnt - 1); i >= 0; --i) {
6117b13bc96SSascha Wildner hcb = sc->hcbs + i;
6127b13bc96SSascha Wildner SLIST_INSERT_HEAD(&sc->free_list, hcb, links);
6137b13bc96SSascha Wildner }
6147b13bc96SSascha Wildner
6157b13bc96SSascha Wildner fail:
6167b13bc96SSascha Wildner if (error) {
6177b13bc96SSascha Wildner pvscsi_dma_free_per_hcb(sc, i);
6187b13bc96SSascha Wildner }
6197b13bc96SSascha Wildner
6207b13bc96SSascha Wildner return (error);
6217b13bc96SSascha Wildner }
6227b13bc96SSascha Wildner
6237b13bc96SSascha Wildner static void
pvscsi_free_rings(struct pvscsi_softc * sc)6247b13bc96SSascha Wildner pvscsi_free_rings(struct pvscsi_softc *sc)
6257b13bc96SSascha Wildner {
6267b13bc96SSascha Wildner
6277b13bc96SSascha Wildner pvscsi_dma_free(sc, &sc->rings_state_dma);
6287b13bc96SSascha Wildner pvscsi_dma_free(sc, &sc->req_ring_dma);
6297b13bc96SSascha Wildner pvscsi_dma_free(sc, &sc->cmp_ring_dma);
6307b13bc96SSascha Wildner if (sc->use_msg) {
6317b13bc96SSascha Wildner pvscsi_dma_free(sc, &sc->msg_ring_dma);
6327b13bc96SSascha Wildner }
6337b13bc96SSascha Wildner }
6347b13bc96SSascha Wildner
6357b13bc96SSascha Wildner static int
pvscsi_allocate_rings(struct pvscsi_softc * sc)6367b13bc96SSascha Wildner pvscsi_allocate_rings(struct pvscsi_softc *sc)
6377b13bc96SSascha Wildner {
6387b13bc96SSascha Wildner int error;
6397b13bc96SSascha Wildner
6407b13bc96SSascha Wildner error = pvscsi_dma_alloc_ppns(sc, &sc->rings_state_dma,
6417b13bc96SSascha Wildner &sc->rings_state_ppn, 1);
6427b13bc96SSascha Wildner if (error) {
6437b13bc96SSascha Wildner device_printf(sc->dev,
6447b13bc96SSascha Wildner "Error allocating rings state, error = %d\n", error);
6457b13bc96SSascha Wildner goto fail;
6467b13bc96SSascha Wildner }
6477b13bc96SSascha Wildner sc->rings_state = sc->rings_state_dma.vaddr;
6487b13bc96SSascha Wildner
6497b13bc96SSascha Wildner error = pvscsi_dma_alloc_ppns(sc, &sc->req_ring_dma, sc->req_ring_ppn,
6507b13bc96SSascha Wildner sc->req_ring_num_pages);
6517b13bc96SSascha Wildner if (error) {
6527b13bc96SSascha Wildner device_printf(sc->dev,
6537b13bc96SSascha Wildner "Error allocating req ring pages, error = %d\n", error);
6547b13bc96SSascha Wildner goto fail;
6557b13bc96SSascha Wildner }
6567b13bc96SSascha Wildner sc->req_ring = sc->req_ring_dma.vaddr;
6577b13bc96SSascha Wildner
6587b13bc96SSascha Wildner error = pvscsi_dma_alloc_ppns(sc, &sc->cmp_ring_dma, sc->cmp_ring_ppn,
6597b13bc96SSascha Wildner sc->cmp_ring_num_pages);
6607b13bc96SSascha Wildner if (error) {
6617b13bc96SSascha Wildner device_printf(sc->dev,
6627b13bc96SSascha Wildner "Error allocating cmp ring pages, error = %d\n", error);
6637b13bc96SSascha Wildner goto fail;
6647b13bc96SSascha Wildner }
6657b13bc96SSascha Wildner sc->cmp_ring = sc->cmp_ring_dma.vaddr;
6667b13bc96SSascha Wildner
6677b13bc96SSascha Wildner sc->msg_ring = NULL;
6687b13bc96SSascha Wildner if (sc->use_msg) {
6697b13bc96SSascha Wildner error = pvscsi_dma_alloc_ppns(sc, &sc->msg_ring_dma,
6707b13bc96SSascha Wildner sc->msg_ring_ppn, sc->msg_ring_num_pages);
6717b13bc96SSascha Wildner if (error) {
6727b13bc96SSascha Wildner device_printf(sc->dev,
6737b13bc96SSascha Wildner "Error allocating cmp ring pages, error = %d\n",
6747b13bc96SSascha Wildner error);
6757b13bc96SSascha Wildner goto fail;
6767b13bc96SSascha Wildner }
6777b13bc96SSascha Wildner sc->msg_ring = sc->msg_ring_dma.vaddr;
6787b13bc96SSascha Wildner }
6797b13bc96SSascha Wildner
6807b13bc96SSascha Wildner DEBUG_PRINTF(1, sc->dev, "rings_state: %p\n", sc->rings_state);
6817b13bc96SSascha Wildner DEBUG_PRINTF(1, sc->dev, "req_ring: %p - %u pages\n", sc->req_ring,
6827b13bc96SSascha Wildner sc->req_ring_num_pages);
6837b13bc96SSascha Wildner DEBUG_PRINTF(1, sc->dev, "cmp_ring: %p - %u pages\n", sc->cmp_ring,
6847b13bc96SSascha Wildner sc->cmp_ring_num_pages);
6857b13bc96SSascha Wildner DEBUG_PRINTF(1, sc->dev, "msg_ring: %p - %u pages\n", sc->msg_ring,
6867b13bc96SSascha Wildner sc->msg_ring_num_pages);
6877b13bc96SSascha Wildner
6887b13bc96SSascha Wildner fail:
6897b13bc96SSascha Wildner if (error) {
6907b13bc96SSascha Wildner pvscsi_free_rings(sc);
6917b13bc96SSascha Wildner }
6927b13bc96SSascha Wildner return (error);
6937b13bc96SSascha Wildner }
6947b13bc96SSascha Wildner
6957b13bc96SSascha Wildner static void
pvscsi_setup_rings(struct pvscsi_softc * sc)6967b13bc96SSascha Wildner pvscsi_setup_rings(struct pvscsi_softc *sc)
6977b13bc96SSascha Wildner {
6987b13bc96SSascha Wildner struct pvscsi_cmd_desc_setup_rings cmd;
6997b13bc96SSascha Wildner uint32_t i;
7007b13bc96SSascha Wildner
7017b13bc96SSascha Wildner bzero(&cmd, sizeof(cmd));
7027b13bc96SSascha Wildner
7037b13bc96SSascha Wildner cmd.rings_state_ppn = sc->rings_state_ppn;
7047b13bc96SSascha Wildner
7057b13bc96SSascha Wildner cmd.req_ring_num_pages = sc->req_ring_num_pages;
7067b13bc96SSascha Wildner for (i = 0; i < sc->req_ring_num_pages; ++i) {
7077b13bc96SSascha Wildner cmd.req_ring_ppns[i] = sc->req_ring_ppn[i];
7087b13bc96SSascha Wildner }
7097b13bc96SSascha Wildner
7107b13bc96SSascha Wildner cmd.cmp_ring_num_pages = sc->cmp_ring_num_pages;
7117b13bc96SSascha Wildner for (i = 0; i < sc->cmp_ring_num_pages; ++i) {
7127b13bc96SSascha Wildner cmd.cmp_ring_ppns[i] = sc->cmp_ring_ppn[i];
7137b13bc96SSascha Wildner }
7147b13bc96SSascha Wildner
7157b13bc96SSascha Wildner pvscsi_write_cmd(sc, PVSCSI_CMD_SETUP_RINGS, &cmd, sizeof(cmd));
7167b13bc96SSascha Wildner }
7177b13bc96SSascha Wildner
7187b13bc96SSascha Wildner static int
pvscsi_hw_supports_msg(struct pvscsi_softc * sc)7197b13bc96SSascha Wildner pvscsi_hw_supports_msg(struct pvscsi_softc *sc)
7207b13bc96SSascha Wildner {
7217b13bc96SSascha Wildner uint32_t status;
7227b13bc96SSascha Wildner
7237b13bc96SSascha Wildner pvscsi_reg_write(sc, PVSCSI_REG_OFFSET_COMMAND,
7247b13bc96SSascha Wildner PVSCSI_CMD_SETUP_MSG_RING);
7257b13bc96SSascha Wildner status = pvscsi_reg_read(sc, PVSCSI_REG_OFFSET_COMMAND_STATUS);
7267b13bc96SSascha Wildner
7277b13bc96SSascha Wildner return (status != -1);
7287b13bc96SSascha Wildner }
7297b13bc96SSascha Wildner
7307b13bc96SSascha Wildner static void
pvscsi_setup_msg_ring(struct pvscsi_softc * sc)7317b13bc96SSascha Wildner pvscsi_setup_msg_ring(struct pvscsi_softc *sc)
7327b13bc96SSascha Wildner {
7337b13bc96SSascha Wildner struct pvscsi_cmd_desc_setup_msg_ring cmd;
7347b13bc96SSascha Wildner uint32_t i;
7357b13bc96SSascha Wildner
7367b13bc96SSascha Wildner KASSERT(sc->use_msg, ("msg is not being used"));
7377b13bc96SSascha Wildner
7387b13bc96SSascha Wildner bzero(&cmd, sizeof(cmd));
7397b13bc96SSascha Wildner
7407b13bc96SSascha Wildner cmd.num_pages = sc->msg_ring_num_pages;
7417b13bc96SSascha Wildner for (i = 0; i < sc->msg_ring_num_pages; ++i) {
7427b13bc96SSascha Wildner cmd.ring_ppns[i] = sc->msg_ring_ppn[i];
7437b13bc96SSascha Wildner }
7447b13bc96SSascha Wildner
7457b13bc96SSascha Wildner pvscsi_write_cmd(sc, PVSCSI_CMD_SETUP_MSG_RING, &cmd, sizeof(cmd));
7467b13bc96SSascha Wildner }
7477b13bc96SSascha Wildner
7487b13bc96SSascha Wildner static void
pvscsi_adapter_reset(struct pvscsi_softc * sc)7497b13bc96SSascha Wildner pvscsi_adapter_reset(struct pvscsi_softc *sc)
7507b13bc96SSascha Wildner {
7511c0b11abSSascha Wildner uint32_t val;
7527b13bc96SSascha Wildner
7537b13bc96SSascha Wildner device_printf(sc->dev, "Adapter Reset\n");
7547b13bc96SSascha Wildner
7557b13bc96SSascha Wildner pvscsi_write_cmd(sc, PVSCSI_CMD_ADAPTER_RESET, NULL, 0);
7567b13bc96SSascha Wildner val = pvscsi_read_intr_status(sc);
7577b13bc96SSascha Wildner
7587b13bc96SSascha Wildner DEBUG_PRINTF(2, sc->dev, "adapter reset done: %u\n", val);
7597b13bc96SSascha Wildner }
7607b13bc96SSascha Wildner
7617b13bc96SSascha Wildner static void
pvscsi_bus_reset(struct pvscsi_softc * sc)7627b13bc96SSascha Wildner pvscsi_bus_reset(struct pvscsi_softc *sc)
7637b13bc96SSascha Wildner {
7647b13bc96SSascha Wildner
7657b13bc96SSascha Wildner device_printf(sc->dev, "Bus Reset\n");
7667b13bc96SSascha Wildner
7677b13bc96SSascha Wildner pvscsi_write_cmd(sc, PVSCSI_CMD_RESET_BUS, NULL, 0);
7687b13bc96SSascha Wildner pvscsi_process_cmp_ring(sc);
7697b13bc96SSascha Wildner
7707b13bc96SSascha Wildner DEBUG_PRINTF(2, sc->dev, "bus reset done\n");
7717b13bc96SSascha Wildner }
7727b13bc96SSascha Wildner
7737b13bc96SSascha Wildner static void
pvscsi_device_reset(struct pvscsi_softc * sc,uint32_t target)7747b13bc96SSascha Wildner pvscsi_device_reset(struct pvscsi_softc *sc, uint32_t target)
7757b13bc96SSascha Wildner {
7767b13bc96SSascha Wildner struct pvscsi_cmd_desc_reset_device cmd;
7777b13bc96SSascha Wildner
7787b13bc96SSascha Wildner memset(&cmd, 0, sizeof(cmd));
7797b13bc96SSascha Wildner
7807b13bc96SSascha Wildner cmd.target = target;
7817b13bc96SSascha Wildner
7827b13bc96SSascha Wildner device_printf(sc->dev, "Device reset for target %u\n", target);
7837b13bc96SSascha Wildner
7847b13bc96SSascha Wildner pvscsi_write_cmd(sc, PVSCSI_CMD_RESET_DEVICE, &cmd, sizeof cmd);
7857b13bc96SSascha Wildner pvscsi_process_cmp_ring(sc);
7867b13bc96SSascha Wildner
7877b13bc96SSascha Wildner DEBUG_PRINTF(2, sc->dev, "device reset done\n");
7887b13bc96SSascha Wildner }
7897b13bc96SSascha Wildner
7907b13bc96SSascha Wildner static void
pvscsi_abort(struct pvscsi_softc * sc,uint32_t target,union ccb * ccb)7917b13bc96SSascha Wildner pvscsi_abort(struct pvscsi_softc *sc, uint32_t target, union ccb *ccb)
7927b13bc96SSascha Wildner {
7937b13bc96SSascha Wildner struct pvscsi_cmd_desc_abort_cmd cmd;
7947b13bc96SSascha Wildner struct pvscsi_hcb *hcb;
7957b13bc96SSascha Wildner uint64_t context;
7967b13bc96SSascha Wildner
7977b13bc96SSascha Wildner pvscsi_process_cmp_ring(sc);
7987b13bc96SSascha Wildner
7997b13bc96SSascha Wildner hcb = ccb->ccb_h.ccb_pvscsi_hcb;
8007b13bc96SSascha Wildner
8017b13bc96SSascha Wildner if (hcb != NULL) {
8027b13bc96SSascha Wildner context = pvscsi_hcb_to_context(sc, hcb);
8037b13bc96SSascha Wildner
8047b13bc96SSascha Wildner memset(&cmd, 0, sizeof cmd);
8057b13bc96SSascha Wildner cmd.target = target;
8067b13bc96SSascha Wildner cmd.context = context;
8077b13bc96SSascha Wildner
8087b13bc96SSascha Wildner device_printf(sc->dev, "Abort for target %u context %llx\n",
8097b13bc96SSascha Wildner target, (unsigned long long)context);
8107b13bc96SSascha Wildner
8117b13bc96SSascha Wildner pvscsi_write_cmd(sc, PVSCSI_CMD_ABORT_CMD, &cmd, sizeof(cmd));
8127b13bc96SSascha Wildner pvscsi_process_cmp_ring(sc);
8137b13bc96SSascha Wildner
8147b13bc96SSascha Wildner DEBUG_PRINTF(2, sc->dev, "abort done\n");
8157b13bc96SSascha Wildner } else {
8167b13bc96SSascha Wildner DEBUG_PRINTF(1, sc->dev,
8177b13bc96SSascha Wildner "Target %u ccb %p not found for abort\n", target, ccb);
8187b13bc96SSascha Wildner }
8197b13bc96SSascha Wildner }
8207b13bc96SSascha Wildner
8217b13bc96SSascha Wildner static int
pvscsi_probe(device_t dev)8227b13bc96SSascha Wildner pvscsi_probe(device_t dev)
8237b13bc96SSascha Wildner {
8247b13bc96SSascha Wildner
8257b13bc96SSascha Wildner if (pci_get_vendor(dev) == PCI_VENDOR_ID_VMWARE &&
8267b13bc96SSascha Wildner pci_get_device(dev) == PCI_DEVICE_ID_VMWARE_PVSCSI) {
8277b13bc96SSascha Wildner device_set_desc(dev, "VMware Paravirtual SCSI Controller");
8287b13bc96SSascha Wildner return (BUS_PROBE_DEFAULT);
8297b13bc96SSascha Wildner }
8307b13bc96SSascha Wildner return (ENXIO);
8317b13bc96SSascha Wildner }
8327b13bc96SSascha Wildner
8337b13bc96SSascha Wildner static int
pvscsi_shutdown(device_t dev)8347b13bc96SSascha Wildner pvscsi_shutdown(device_t dev)
8357b13bc96SSascha Wildner {
8367b13bc96SSascha Wildner
8377b13bc96SSascha Wildner return (0);
8387b13bc96SSascha Wildner }
8397b13bc96SSascha Wildner
8407b13bc96SSascha Wildner static void
pvscsi_timeout(void * arg)8417b13bc96SSascha Wildner pvscsi_timeout(void *arg)
8427b13bc96SSascha Wildner {
8437b13bc96SSascha Wildner struct pvscsi_hcb *hcb;
8447b13bc96SSascha Wildner struct pvscsi_softc *sc;
8457b13bc96SSascha Wildner union ccb *ccb;
8467b13bc96SSascha Wildner
8477b13bc96SSascha Wildner hcb = arg;
8487b13bc96SSascha Wildner ccb = hcb->ccb;
8497b13bc96SSascha Wildner
8507b13bc96SSascha Wildner if (ccb == NULL) {
8517b13bc96SSascha Wildner /* Already completed */
8527b13bc96SSascha Wildner return;
8537b13bc96SSascha Wildner }
8547b13bc96SSascha Wildner
8557b13bc96SSascha Wildner sc = ccb->ccb_h.ccb_pvscsi_sc;
8561c0b11abSSascha Wildner KKASSERT(lockowned(&sc->lock));
8577b13bc96SSascha Wildner
8587b13bc96SSascha Wildner device_printf(sc->dev, "Command timed out hcb=%p ccb=%p.\n", hcb, ccb);
8597b13bc96SSascha Wildner
8607b13bc96SSascha Wildner switch (hcb->recovery) {
8617b13bc96SSascha Wildner case PVSCSI_HCB_NONE:
8627b13bc96SSascha Wildner hcb->recovery = PVSCSI_HCB_ABORT;
8637b13bc96SSascha Wildner pvscsi_abort(sc, ccb->ccb_h.target_id, ccb);
8641c0b11abSSascha Wildner callout_reset(&hcb->callout, (PVSCSI_ABORT_TIMEOUT * hz) / 1000,
8651c0b11abSSascha Wildner pvscsi_timeout, hcb);
8667b13bc96SSascha Wildner break;
8677b13bc96SSascha Wildner case PVSCSI_HCB_ABORT:
8687b13bc96SSascha Wildner hcb->recovery = PVSCSI_HCB_DEVICE_RESET;
8697b13bc96SSascha Wildner pvscsi_freeze(sc);
8707b13bc96SSascha Wildner pvscsi_device_reset(sc, ccb->ccb_h.target_id);
8711c0b11abSSascha Wildner callout_reset(&hcb->callout, (PVSCSI_RESET_TIMEOUT * hz) / 1000,
8721c0b11abSSascha Wildner pvscsi_timeout, hcb);
8737b13bc96SSascha Wildner break;
8747b13bc96SSascha Wildner case PVSCSI_HCB_DEVICE_RESET:
8757b13bc96SSascha Wildner hcb->recovery = PVSCSI_HCB_BUS_RESET;
8767b13bc96SSascha Wildner pvscsi_freeze(sc);
8777b13bc96SSascha Wildner pvscsi_bus_reset(sc);
8781c0b11abSSascha Wildner callout_reset(&hcb->callout, (PVSCSI_RESET_TIMEOUT * hz) / 1000,
8791c0b11abSSascha Wildner pvscsi_timeout, hcb);
8807b13bc96SSascha Wildner break;
8817b13bc96SSascha Wildner case PVSCSI_HCB_BUS_RESET:
8827b13bc96SSascha Wildner pvscsi_freeze(sc);
8837b13bc96SSascha Wildner pvscsi_adapter_reset(sc);
8847b13bc96SSascha Wildner break;
8857b13bc96SSascha Wildner };
8867b13bc96SSascha Wildner }
8877b13bc96SSascha Wildner
8887b13bc96SSascha Wildner static void
pvscsi_process_completion(struct pvscsi_softc * sc,struct pvscsi_ring_cmp_desc * e)8897b13bc96SSascha Wildner pvscsi_process_completion(struct pvscsi_softc *sc,
8907b13bc96SSascha Wildner struct pvscsi_ring_cmp_desc *e)
8917b13bc96SSascha Wildner {
8927b13bc96SSascha Wildner struct pvscsi_hcb *hcb;
8937b13bc96SSascha Wildner union ccb *ccb;
8947b13bc96SSascha Wildner uint32_t status;
8957b13bc96SSascha Wildner uint32_t btstat;
8967b13bc96SSascha Wildner uint32_t sdstat;
8977b13bc96SSascha Wildner bus_dmasync_op_t op;
8987b13bc96SSascha Wildner
8997b13bc96SSascha Wildner hcb = pvscsi_context_to_hcb(sc, e->context);
9007b13bc96SSascha Wildner
9017b13bc96SSascha Wildner callout_stop(&hcb->callout);
9027b13bc96SSascha Wildner
9037b13bc96SSascha Wildner ccb = hcb->ccb;
9047b13bc96SSascha Wildner
9057b13bc96SSascha Wildner btstat = e->host_status;
9067b13bc96SSascha Wildner sdstat = e->scsi_status;
9077b13bc96SSascha Wildner
9087b13bc96SSascha Wildner ccb->csio.scsi_status = sdstat;
9097b13bc96SSascha Wildner ccb->csio.resid = ccb->csio.dxfer_len - e->data_len;
9107b13bc96SSascha Wildner
9117b13bc96SSascha Wildner if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
9127b13bc96SSascha Wildner if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
9137b13bc96SSascha Wildner op = BUS_DMASYNC_POSTREAD;
9147b13bc96SSascha Wildner } else {
9157b13bc96SSascha Wildner op = BUS_DMASYNC_POSTWRITE;
9167b13bc96SSascha Wildner }
9177b13bc96SSascha Wildner bus_dmamap_sync(sc->buffer_dmat, hcb->dma_map, op);
9187b13bc96SSascha Wildner bus_dmamap_unload(sc->buffer_dmat, hcb->dma_map);
9197b13bc96SSascha Wildner }
9207b13bc96SSascha Wildner
9217b13bc96SSascha Wildner if (btstat == BTSTAT_SUCCESS && sdstat == SCSI_STATUS_OK) {
9227b13bc96SSascha Wildner DEBUG_PRINTF(3, sc->dev,
9237b13bc96SSascha Wildner "completing command context %llx success\n",
9247b13bc96SSascha Wildner (unsigned long long)e->context);
9257b13bc96SSascha Wildner ccb->csio.resid = 0;
9267b13bc96SSascha Wildner status = CAM_REQ_CMP;
9277b13bc96SSascha Wildner } else {
9287b13bc96SSascha Wildner switch (btstat) {
9297b13bc96SSascha Wildner case BTSTAT_SUCCESS:
9307b13bc96SSascha Wildner case BTSTAT_LINKED_COMMAND_COMPLETED:
9317b13bc96SSascha Wildner case BTSTAT_LINKED_COMMAND_COMPLETED_WITH_FLAG:
9327b13bc96SSascha Wildner switch (sdstat) {
9337b13bc96SSascha Wildner case SCSI_STATUS_OK:
9347b13bc96SSascha Wildner ccb->csio.resid = 0;
9357b13bc96SSascha Wildner status = CAM_REQ_CMP;
9367b13bc96SSascha Wildner break;
9377b13bc96SSascha Wildner case SCSI_STATUS_CHECK_COND:
9387b13bc96SSascha Wildner status = CAM_SCSI_STATUS_ERROR;
9397b13bc96SSascha Wildner
9407b13bc96SSascha Wildner if (ccb->csio.sense_len != 0) {
9417b13bc96SSascha Wildner status |= CAM_AUTOSNS_VALID;
9427b13bc96SSascha Wildner
9437b13bc96SSascha Wildner memset(&ccb->csio.sense_data, 0,
9447b13bc96SSascha Wildner sizeof(ccb->csio.sense_data));
9457b13bc96SSascha Wildner memcpy(&ccb->csio.sense_data,
9467b13bc96SSascha Wildner hcb->sense_buffer,
9477b13bc96SSascha Wildner MIN(ccb->csio.sense_len,
9487b13bc96SSascha Wildner e->sense_len));
9497b13bc96SSascha Wildner }
9507b13bc96SSascha Wildner break;
9517b13bc96SSascha Wildner case SCSI_STATUS_BUSY:
9527b13bc96SSascha Wildner case SCSI_STATUS_QUEUE_FULL:
9537b13bc96SSascha Wildner status = CAM_REQUEUE_REQ;
9547b13bc96SSascha Wildner break;
9557b13bc96SSascha Wildner case SCSI_STATUS_CMD_TERMINATED:
9567b13bc96SSascha Wildner case SCSI_STATUS_TASK_ABORTED:
9577b13bc96SSascha Wildner status = CAM_REQ_ABORTED;
9587b13bc96SSascha Wildner break;
9597b13bc96SSascha Wildner default:
9607b13bc96SSascha Wildner DEBUG_PRINTF(1, sc->dev,
9617b13bc96SSascha Wildner "ccb: %p sdstat=0x%x\n", ccb, sdstat);
9627b13bc96SSascha Wildner status = CAM_SCSI_STATUS_ERROR;
9637b13bc96SSascha Wildner break;
9647b13bc96SSascha Wildner }
9657b13bc96SSascha Wildner break;
9667b13bc96SSascha Wildner case BTSTAT_SELTIMEO:
9677b13bc96SSascha Wildner status = CAM_SEL_TIMEOUT;
9687b13bc96SSascha Wildner break;
9697b13bc96SSascha Wildner case BTSTAT_DATARUN:
9707b13bc96SSascha Wildner case BTSTAT_DATA_UNDERRUN:
9717b13bc96SSascha Wildner status = CAM_DATA_RUN_ERR;
9727b13bc96SSascha Wildner break;
9737b13bc96SSascha Wildner case BTSTAT_ABORTQUEUE:
9747b13bc96SSascha Wildner case BTSTAT_HATIMEOUT:
9757b13bc96SSascha Wildner status = CAM_REQUEUE_REQ;
9767b13bc96SSascha Wildner break;
9777b13bc96SSascha Wildner case BTSTAT_NORESPONSE:
9787b13bc96SSascha Wildner case BTSTAT_SENTRST:
9797b13bc96SSascha Wildner case BTSTAT_RECVRST:
9807b13bc96SSascha Wildner case BTSTAT_BUSRESET:
9817b13bc96SSascha Wildner status = CAM_SCSI_BUS_RESET;
9827b13bc96SSascha Wildner break;
9837b13bc96SSascha Wildner case BTSTAT_SCSIPARITY:
9847b13bc96SSascha Wildner status = CAM_UNCOR_PARITY;
9857b13bc96SSascha Wildner break;
9867b13bc96SSascha Wildner case BTSTAT_BUSFREE:
9877b13bc96SSascha Wildner status = CAM_UNEXP_BUSFREE;
9887b13bc96SSascha Wildner break;
9897b13bc96SSascha Wildner case BTSTAT_INVPHASE:
9907b13bc96SSascha Wildner status = CAM_SEQUENCE_FAIL;
9917b13bc96SSascha Wildner break;
9927b13bc96SSascha Wildner case BTSTAT_SENSFAILED:
9937b13bc96SSascha Wildner status = CAM_AUTOSENSE_FAIL;
9947b13bc96SSascha Wildner break;
9957b13bc96SSascha Wildner case BTSTAT_LUNMISMATCH:
9967b13bc96SSascha Wildner case BTSTAT_TAGREJECT:
9977b13bc96SSascha Wildner case BTSTAT_DISCONNECT:
9987b13bc96SSascha Wildner case BTSTAT_BADMSG:
9997b13bc96SSascha Wildner case BTSTAT_INVPARAM:
10007b13bc96SSascha Wildner status = CAM_REQ_CMP_ERR;
10017b13bc96SSascha Wildner break;
10027b13bc96SSascha Wildner case BTSTAT_HASOFTWARE:
10037b13bc96SSascha Wildner case BTSTAT_HAHARDWARE:
10047b13bc96SSascha Wildner status = CAM_NO_HBA;
10057b13bc96SSascha Wildner break;
10067b13bc96SSascha Wildner default:
10077b13bc96SSascha Wildner device_printf(sc->dev, "unknown hba status: 0x%x\n",
10087b13bc96SSascha Wildner btstat);
10097b13bc96SSascha Wildner status = CAM_NO_HBA;
10107b13bc96SSascha Wildner break;
10117b13bc96SSascha Wildner }
10127b13bc96SSascha Wildner
10137b13bc96SSascha Wildner DEBUG_PRINTF(3, sc->dev,
10147b13bc96SSascha Wildner "completing command context %llx btstat %x sdstat %x - status %x\n",
10157b13bc96SSascha Wildner (unsigned long long)e->context, btstat, sdstat, status);
10167b13bc96SSascha Wildner }
10177b13bc96SSascha Wildner
10187b13bc96SSascha Wildner ccb->ccb_h.ccb_pvscsi_hcb = NULL;
10197b13bc96SSascha Wildner ccb->ccb_h.ccb_pvscsi_sc = NULL;
10207b13bc96SSascha Wildner pvscsi_hcb_put(sc, hcb);
10217b13bc96SSascha Wildner
10227b13bc96SSascha Wildner ccb->ccb_h.status =
10237b13bc96SSascha Wildner status | (ccb->ccb_h.status & ~(CAM_STATUS_MASK | CAM_SIM_QUEUED));
10247b13bc96SSascha Wildner
10257b13bc96SSascha Wildner if (sc->frozen) {
10267b13bc96SSascha Wildner ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
10277b13bc96SSascha Wildner sc->frozen = 0;
10287b13bc96SSascha Wildner }
10297b13bc96SSascha Wildner
10307b13bc96SSascha Wildner if (status != CAM_REQ_CMP) {
10317b13bc96SSascha Wildner ccb->ccb_h.status |= CAM_DEV_QFRZN;
10327b13bc96SSascha Wildner xpt_freeze_devq(ccb->ccb_h.path, /*count*/ 1);
10337b13bc96SSascha Wildner }
10347b13bc96SSascha Wildner xpt_done(ccb);
10357b13bc96SSascha Wildner }
10367b13bc96SSascha Wildner
10377b13bc96SSascha Wildner static void
pvscsi_process_cmp_ring(struct pvscsi_softc * sc)10387b13bc96SSascha Wildner pvscsi_process_cmp_ring(struct pvscsi_softc *sc)
10397b13bc96SSascha Wildner {
10407b13bc96SSascha Wildner struct pvscsi_ring_cmp_desc *ring;
10417b13bc96SSascha Wildner struct pvscsi_rings_state *s;
10427b13bc96SSascha Wildner struct pvscsi_ring_cmp_desc *e;
10437b13bc96SSascha Wildner uint32_t mask;
10447b13bc96SSascha Wildner
10451c0b11abSSascha Wildner KKASSERT(lockowned(&sc->lock));
10467b13bc96SSascha Wildner
10477b13bc96SSascha Wildner s = sc->rings_state;
10487b13bc96SSascha Wildner ring = sc->cmp_ring;
10497b13bc96SSascha Wildner mask = MASK(s->cmp_num_entries_log2);
10507b13bc96SSascha Wildner
10517b13bc96SSascha Wildner while (s->cmp_cons_idx != s->cmp_prod_idx) {
10527b13bc96SSascha Wildner e = ring + (s->cmp_cons_idx & mask);
10537b13bc96SSascha Wildner
10547b13bc96SSascha Wildner pvscsi_process_completion(sc, e);
10557b13bc96SSascha Wildner
10561c0b11abSSascha Wildner cpu_mfence();
10577b13bc96SSascha Wildner s->cmp_cons_idx++;
10587b13bc96SSascha Wildner }
10597b13bc96SSascha Wildner }
10607b13bc96SSascha Wildner
10617b13bc96SSascha Wildner static void
pvscsi_rescan_callback(struct cam_periph * periph,union ccb * ccb)10621c0b11abSSascha Wildner pvscsi_rescan_callback(struct cam_periph *periph, union ccb *ccb)
10631c0b11abSSascha Wildner {
10641c0b11abSSascha Wildner if (ccb->ccb_h.status != CAM_REQ_CMP)
10651c0b11abSSascha Wildner kprintf("%s: failure status = %x\n", __func__,
10661c0b11abSSascha Wildner ccb->ccb_h.status);
10671c0b11abSSascha Wildner
10681c0b11abSSascha Wildner xpt_free_path(ccb->ccb_h.path);
10691c0b11abSSascha Wildner xpt_free_ccb(&ccb->ccb_h);
10701c0b11abSSascha Wildner }
10711c0b11abSSascha Wildner
10721c0b11abSSascha Wildner static void
pvscsi_process_msg(struct pvscsi_softc * sc,struct pvscsi_ring_msg_desc * e)10737b13bc96SSascha Wildner pvscsi_process_msg(struct pvscsi_softc *sc, struct pvscsi_ring_msg_desc *e)
10747b13bc96SSascha Wildner {
10757b13bc96SSascha Wildner struct pvscsi_ring_msg_dev_status_changed *desc;
10767b13bc96SSascha Wildner union ccb *ccb;
10771c0b11abSSascha Wildner
10787b13bc96SSascha Wildner switch (e->type) {
10797b13bc96SSascha Wildner case PVSCSI_MSG_DEV_ADDED:
10807b13bc96SSascha Wildner case PVSCSI_MSG_DEV_REMOVED: {
10817b13bc96SSascha Wildner desc = (struct pvscsi_ring_msg_dev_status_changed *)e;
10827b13bc96SSascha Wildner
10837b13bc96SSascha Wildner device_printf(sc->dev, "MSG: device %s at scsi%u:%u:%u\n",
10847b13bc96SSascha Wildner desc->type == PVSCSI_MSG_DEV_ADDED ? "addition" : "removal",
10857b13bc96SSascha Wildner desc->bus, desc->target, desc->lun[1]);
10867b13bc96SSascha Wildner
10871c0b11abSSascha Wildner ccb = xpt_alloc_ccb();
10887b13bc96SSascha Wildner if (ccb == NULL) {
10897b13bc96SSascha Wildner device_printf(sc->dev,
10907b13bc96SSascha Wildner "Error allocating CCB for dev change.\n");
10917b13bc96SSascha Wildner break;
10927b13bc96SSascha Wildner }
10937b13bc96SSascha Wildner
10947b13bc96SSascha Wildner if (xpt_create_path(&ccb->ccb_h.path, NULL,
10957b13bc96SSascha Wildner cam_sim_path(sc->sim), desc->target, desc->lun[1])
10967b13bc96SSascha Wildner != CAM_REQ_CMP) {
10977b13bc96SSascha Wildner device_printf(sc->dev,
10987b13bc96SSascha Wildner "Error creating path for dev change.\n");
10991c0b11abSSascha Wildner xpt_free_ccb(&ccb->ccb_h);
11007b13bc96SSascha Wildner break;
11017b13bc96SSascha Wildner }
11027b13bc96SSascha Wildner
11031c0b11abSSascha Wildner xpt_setup_ccb(&ccb->ccb_h, ccb->ccb_h.path, /*lowpri*/5);
11041c0b11abSSascha Wildner ccb->ccb_h.func_code = XPT_SCAN_LUN;
11051c0b11abSSascha Wildner ccb->ccb_h.cbfcnp = pvscsi_rescan_callback;
11061c0b11abSSascha Wildner ccb->crcn.flags = CAM_FLAG_NONE;
11071c0b11abSSascha Wildner xpt_action(ccb);
11087b13bc96SSascha Wildner } break;
11097b13bc96SSascha Wildner default:
11107b13bc96SSascha Wildner device_printf(sc->dev, "Unknown msg type 0x%x\n", e->type);
11117b13bc96SSascha Wildner };
11127b13bc96SSascha Wildner }
11137b13bc96SSascha Wildner
11147b13bc96SSascha Wildner static void
pvscsi_process_msg_ring(struct pvscsi_softc * sc)11157b13bc96SSascha Wildner pvscsi_process_msg_ring(struct pvscsi_softc *sc)
11167b13bc96SSascha Wildner {
11177b13bc96SSascha Wildner struct pvscsi_ring_msg_desc *ring;
11187b13bc96SSascha Wildner struct pvscsi_rings_state *s;
11197b13bc96SSascha Wildner struct pvscsi_ring_msg_desc *e;
11207b13bc96SSascha Wildner uint32_t mask;
11217b13bc96SSascha Wildner
11221c0b11abSSascha Wildner KKASSERT(lockowned(&sc->lock));
11237b13bc96SSascha Wildner
11247b13bc96SSascha Wildner s = sc->rings_state;
11257b13bc96SSascha Wildner ring = sc->msg_ring;
11267b13bc96SSascha Wildner mask = MASK(s->msg_num_entries_log2);
11277b13bc96SSascha Wildner
11287b13bc96SSascha Wildner while (s->msg_cons_idx != s->msg_prod_idx) {
11297b13bc96SSascha Wildner e = ring + (s->msg_cons_idx & mask);
11307b13bc96SSascha Wildner
11317b13bc96SSascha Wildner pvscsi_process_msg(sc, e);
11327b13bc96SSascha Wildner
11331c0b11abSSascha Wildner cpu_mfence();
11347b13bc96SSascha Wildner s->msg_cons_idx++;
11357b13bc96SSascha Wildner }
11367b13bc96SSascha Wildner }
11377b13bc96SSascha Wildner
11387b13bc96SSascha Wildner static void
pvscsi_intr_locked(struct pvscsi_softc * sc)11397b13bc96SSascha Wildner pvscsi_intr_locked(struct pvscsi_softc *sc)
11407b13bc96SSascha Wildner {
11417b13bc96SSascha Wildner uint32_t val;
11427b13bc96SSascha Wildner
11431c0b11abSSascha Wildner KKASSERT(lockowned(&sc->lock));
11447b13bc96SSascha Wildner
11457b13bc96SSascha Wildner val = pvscsi_read_intr_status(sc);
11467b13bc96SSascha Wildner
11477b13bc96SSascha Wildner if ((val & PVSCSI_INTR_ALL_SUPPORTED) != 0) {
11487b13bc96SSascha Wildner pvscsi_write_intr_status(sc, val & PVSCSI_INTR_ALL_SUPPORTED);
11497b13bc96SSascha Wildner pvscsi_process_cmp_ring(sc);
11507b13bc96SSascha Wildner if (sc->use_msg) {
11517b13bc96SSascha Wildner pvscsi_process_msg_ring(sc);
11527b13bc96SSascha Wildner }
11537b13bc96SSascha Wildner }
11547b13bc96SSascha Wildner }
11557b13bc96SSascha Wildner
11567b13bc96SSascha Wildner static void
pvscsi_intr(void * xsc)11577b13bc96SSascha Wildner pvscsi_intr(void *xsc)
11587b13bc96SSascha Wildner {
11597b13bc96SSascha Wildner struct pvscsi_softc *sc;
11607b13bc96SSascha Wildner
11617b13bc96SSascha Wildner sc = xsc;
11627b13bc96SSascha Wildner
11631c0b11abSSascha Wildner KKASSERT(!lockowned(&sc->lock));
11647b13bc96SSascha Wildner
11651c0b11abSSascha Wildner lockmgr(&sc->lock, LK_EXCLUSIVE);
11667b13bc96SSascha Wildner pvscsi_intr_locked(xsc);
11671c0b11abSSascha Wildner lockmgr(&sc->lock, LK_RELEASE);
11687b13bc96SSascha Wildner }
11697b13bc96SSascha Wildner
11707b13bc96SSascha Wildner static void
pvscsi_poll(struct cam_sim * sim)11717b13bc96SSascha Wildner pvscsi_poll(struct cam_sim *sim)
11727b13bc96SSascha Wildner {
11737b13bc96SSascha Wildner struct pvscsi_softc *sc;
11747b13bc96SSascha Wildner
11757b13bc96SSascha Wildner sc = cam_sim_softc(sim);
11767b13bc96SSascha Wildner
11771c0b11abSSascha Wildner KKASSERT(lockowned(&sc->lock));
11787b13bc96SSascha Wildner pvscsi_intr_locked(sc);
11797b13bc96SSascha Wildner }
11807b13bc96SSascha Wildner
11817b13bc96SSascha Wildner static void
pvscsi_execute_ccb(void * arg,bus_dma_segment_t * segs,int nseg,int error)11827b13bc96SSascha Wildner pvscsi_execute_ccb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
11837b13bc96SSascha Wildner {
11847b13bc96SSascha Wildner struct pvscsi_hcb *hcb;
11857b13bc96SSascha Wildner struct pvscsi_ring_req_desc *e;
11867b13bc96SSascha Wildner union ccb *ccb;
11877b13bc96SSascha Wildner struct pvscsi_softc *sc;
11887b13bc96SSascha Wildner struct pvscsi_rings_state *s;
11897b13bc96SSascha Wildner uint8_t cdb0;
11907b13bc96SSascha Wildner bus_dmasync_op_t op;
11917b13bc96SSascha Wildner
11927b13bc96SSascha Wildner hcb = arg;
11937b13bc96SSascha Wildner ccb = hcb->ccb;
11947b13bc96SSascha Wildner e = hcb->e;
11957b13bc96SSascha Wildner sc = ccb->ccb_h.ccb_pvscsi_sc;
11967b13bc96SSascha Wildner s = sc->rings_state;
11977b13bc96SSascha Wildner
11981c0b11abSSascha Wildner KKASSERT(lockowned(&sc->lock));
11997b13bc96SSascha Wildner
12007b13bc96SSascha Wildner if (error) {
12017b13bc96SSascha Wildner device_printf(sc->dev, "pvscsi_execute_ccb error %d\n", error);
12027b13bc96SSascha Wildner
12037b13bc96SSascha Wildner if (error == EFBIG) {
12047b13bc96SSascha Wildner ccb->ccb_h.status = CAM_REQ_TOO_BIG;
12057b13bc96SSascha Wildner } else {
12067b13bc96SSascha Wildner ccb->ccb_h.status = CAM_REQ_CMP_ERR;
12077b13bc96SSascha Wildner }
12087b13bc96SSascha Wildner
12097b13bc96SSascha Wildner pvscsi_hcb_put(sc, hcb);
12107b13bc96SSascha Wildner xpt_done(ccb);
12117b13bc96SSascha Wildner return;
12127b13bc96SSascha Wildner }
12137b13bc96SSascha Wildner
12147b13bc96SSascha Wildner e->flags = 0;
12157b13bc96SSascha Wildner op = 0;
12167b13bc96SSascha Wildner switch (ccb->ccb_h.flags & CAM_DIR_MASK) {
12177b13bc96SSascha Wildner case CAM_DIR_NONE:
12187b13bc96SSascha Wildner e->flags |= PVSCSI_FLAG_CMD_DIR_NONE;
12197b13bc96SSascha Wildner break;
12207b13bc96SSascha Wildner case CAM_DIR_IN:
12217b13bc96SSascha Wildner e->flags |= PVSCSI_FLAG_CMD_DIR_TOHOST;
12227b13bc96SSascha Wildner op = BUS_DMASYNC_PREREAD;
12237b13bc96SSascha Wildner break;
12247b13bc96SSascha Wildner case CAM_DIR_OUT:
12257b13bc96SSascha Wildner e->flags |= PVSCSI_FLAG_CMD_DIR_TODEVICE;
12267b13bc96SSascha Wildner op = BUS_DMASYNC_PREWRITE;
12277b13bc96SSascha Wildner break;
12287b13bc96SSascha Wildner }
12297b13bc96SSascha Wildner
12307b13bc96SSascha Wildner if (nseg != 0) {
12317b13bc96SSascha Wildner if (nseg > 1) {
12327b13bc96SSascha Wildner int i;
12337b13bc96SSascha Wildner struct pvscsi_sg_element *sge;
12347b13bc96SSascha Wildner
12357b13bc96SSascha Wildner KASSERT(nseg <= PVSCSI_MAX_SG_ENTRIES_PER_SEGMENT,
12367b13bc96SSascha Wildner ("too many sg segments"));
12377b13bc96SSascha Wildner
12387b13bc96SSascha Wildner sge = hcb->sg_list->sge;
12397b13bc96SSascha Wildner e->flags |= PVSCSI_FLAG_CMD_WITH_SG_LIST;
12407b13bc96SSascha Wildner
12417b13bc96SSascha Wildner for (i = 0; i < nseg; ++i) {
12427b13bc96SSascha Wildner sge[i].addr = segs[i].ds_addr;
12437b13bc96SSascha Wildner sge[i].length = segs[i].ds_len;
12447b13bc96SSascha Wildner sge[i].flags = 0;
12457b13bc96SSascha Wildner }
12467b13bc96SSascha Wildner
12477b13bc96SSascha Wildner e->data_addr = hcb->sg_list_paddr;
12487b13bc96SSascha Wildner } else {
12497b13bc96SSascha Wildner e->data_addr = segs->ds_addr;
12507b13bc96SSascha Wildner }
12517b13bc96SSascha Wildner
12527b13bc96SSascha Wildner bus_dmamap_sync(sc->buffer_dmat, hcb->dma_map, op);
12537b13bc96SSascha Wildner } else {
12547b13bc96SSascha Wildner e->data_addr = 0;
12557b13bc96SSascha Wildner }
12567b13bc96SSascha Wildner
12577b13bc96SSascha Wildner cdb0 = e->cdb[0];
12587b13bc96SSascha Wildner ccb->ccb_h.status |= CAM_SIM_QUEUED;
12597b13bc96SSascha Wildner
12607b13bc96SSascha Wildner if (ccb->ccb_h.timeout != CAM_TIME_INFINITY) {
12611c0b11abSSascha Wildner callout_reset(&hcb->callout, (ccb->ccb_h.timeout * hz) / 1000,
12621c0b11abSSascha Wildner pvscsi_timeout, hcb);
12637b13bc96SSascha Wildner }
12647b13bc96SSascha Wildner
12651c0b11abSSascha Wildner cpu_mfence();
12667b13bc96SSascha Wildner s->req_prod_idx++;
12677b13bc96SSascha Wildner pvscsi_kick_io(sc, cdb0);
12687b13bc96SSascha Wildner }
12697b13bc96SSascha Wildner
12707b13bc96SSascha Wildner static void
pvscsi_action(struct cam_sim * sim,union ccb * ccb)12717b13bc96SSascha Wildner pvscsi_action(struct cam_sim *sim, union ccb *ccb)
12727b13bc96SSascha Wildner {
12737b13bc96SSascha Wildner struct pvscsi_softc *sc;
12747b13bc96SSascha Wildner struct ccb_hdr *ccb_h;
12757b13bc96SSascha Wildner
12767b13bc96SSascha Wildner sc = cam_sim_softc(sim);
12777b13bc96SSascha Wildner ccb_h = &ccb->ccb_h;
12787b13bc96SSascha Wildner
12791c0b11abSSascha Wildner KKASSERT(lockowned(&sc->lock));
12807b13bc96SSascha Wildner
12817b13bc96SSascha Wildner switch (ccb_h->func_code) {
12827b13bc96SSascha Wildner case XPT_SCSI_IO:
12837b13bc96SSascha Wildner {
12847b13bc96SSascha Wildner struct ccb_scsiio *csio;
12857b13bc96SSascha Wildner uint32_t req_num_entries_log2;
12867b13bc96SSascha Wildner struct pvscsi_ring_req_desc *ring;
12877b13bc96SSascha Wildner struct pvscsi_ring_req_desc *e;
12887b13bc96SSascha Wildner struct pvscsi_rings_state *s;
12897b13bc96SSascha Wildner struct pvscsi_hcb *hcb;
12907b13bc96SSascha Wildner
12917b13bc96SSascha Wildner csio = &ccb->csio;
12927b13bc96SSascha Wildner ring = sc->req_ring;
12937b13bc96SSascha Wildner s = sc->rings_state;
12947b13bc96SSascha Wildner
12957b13bc96SSascha Wildner hcb = NULL;
12967b13bc96SSascha Wildner
12977b13bc96SSascha Wildner /*
12987b13bc96SSascha Wildner * Check if it was completed already (such as aborted
12997b13bc96SSascha Wildner * by upper layers)
13007b13bc96SSascha Wildner */
13017b13bc96SSascha Wildner if ((ccb_h->status & CAM_STATUS_MASK) != CAM_REQ_INPROG) {
13027b13bc96SSascha Wildner xpt_done(ccb);
13037b13bc96SSascha Wildner return;
13047b13bc96SSascha Wildner }
13057b13bc96SSascha Wildner
13067b13bc96SSascha Wildner req_num_entries_log2 = s->req_num_entries_log2;
13077b13bc96SSascha Wildner
13087b13bc96SSascha Wildner if (s->req_prod_idx - s->cmp_cons_idx >=
13097b13bc96SSascha Wildner (1 << req_num_entries_log2)) {
13107b13bc96SSascha Wildner device_printf(sc->dev,
13117b13bc96SSascha Wildner "Not enough room on completion ring.\n");
13127b13bc96SSascha Wildner pvscsi_freeze(sc);
13137b13bc96SSascha Wildner ccb_h->status = CAM_REQUEUE_REQ;
13147b13bc96SSascha Wildner goto finish_ccb;
13157b13bc96SSascha Wildner }
13167b13bc96SSascha Wildner
13177b13bc96SSascha Wildner hcb = pvscsi_hcb_get(sc);
13187b13bc96SSascha Wildner if (hcb == NULL) {
13197b13bc96SSascha Wildner device_printf(sc->dev, "No free hcbs.\n");
13207b13bc96SSascha Wildner pvscsi_freeze(sc);
13217b13bc96SSascha Wildner ccb_h->status = CAM_REQUEUE_REQ;
13227b13bc96SSascha Wildner goto finish_ccb;
13237b13bc96SSascha Wildner }
13247b13bc96SSascha Wildner
13257b13bc96SSascha Wildner hcb->ccb = ccb;
13267b13bc96SSascha Wildner ccb_h->ccb_pvscsi_hcb = hcb;
13277b13bc96SSascha Wildner ccb_h->ccb_pvscsi_sc = sc;
13287b13bc96SSascha Wildner
13297b13bc96SSascha Wildner if (csio->cdb_len > sizeof(e->cdb)) {
13307b13bc96SSascha Wildner DEBUG_PRINTF(2, sc->dev, "cdb length %u too large\n",
13317b13bc96SSascha Wildner csio->cdb_len);
13327b13bc96SSascha Wildner ccb_h->status = CAM_REQ_INVALID;
13337b13bc96SSascha Wildner goto finish_ccb;
13347b13bc96SSascha Wildner }
13357b13bc96SSascha Wildner
13367b13bc96SSascha Wildner if (ccb_h->flags & CAM_CDB_PHYS) {
13377b13bc96SSascha Wildner DEBUG_PRINTF(2, sc->dev,
13387b13bc96SSascha Wildner "CAM_CDB_PHYS not implemented\n");
13397b13bc96SSascha Wildner ccb_h->status = CAM_REQ_INVALID;
13407b13bc96SSascha Wildner goto finish_ccb;
13417b13bc96SSascha Wildner }
13427b13bc96SSascha Wildner
13437b13bc96SSascha Wildner e = ring + (s->req_prod_idx & MASK(req_num_entries_log2));
13447b13bc96SSascha Wildner
13457b13bc96SSascha Wildner e->bus = cam_sim_bus(sim);
13467b13bc96SSascha Wildner e->target = ccb_h->target_id;
13477b13bc96SSascha Wildner memset(e->lun, 0, sizeof(e->lun));
13487b13bc96SSascha Wildner e->lun[1] = ccb_h->target_lun;
13497b13bc96SSascha Wildner e->data_addr = 0;
13507b13bc96SSascha Wildner e->data_len = csio->dxfer_len;
13511c0b11abSSascha Wildner e->vcpu_hint = mycpuid;
13527b13bc96SSascha Wildner
13537b13bc96SSascha Wildner e->cdb_len = csio->cdb_len;
13541c0b11abSSascha Wildner if (csio->ccb_h.flags & CAM_CDB_POINTER) {
13551c0b11abSSascha Wildner memcpy(e->cdb, ccb->csio.cdb_io.cdb_ptr,
13561c0b11abSSascha Wildner csio->cdb_len);
13571c0b11abSSascha Wildner } else {
13581c0b11abSSascha Wildner memcpy(e->cdb, ccb->csio.cdb_io.cdb_bytes,
13591c0b11abSSascha Wildner csio->cdb_len);
13601c0b11abSSascha Wildner }
13617b13bc96SSascha Wildner
13627b13bc96SSascha Wildner e->sense_addr = 0;
13637b13bc96SSascha Wildner e->sense_len = csio->sense_len;
13647b13bc96SSascha Wildner if (e->sense_len > 0) {
13657b13bc96SSascha Wildner e->sense_addr = hcb->sense_buffer_paddr;
13667b13bc96SSascha Wildner }
13677b13bc96SSascha Wildner
13687b13bc96SSascha Wildner e->tag = MSG_SIMPLE_Q_TAG;
13697b13bc96SSascha Wildner if (ccb_h->flags & CAM_TAG_ACTION_VALID) {
13707b13bc96SSascha Wildner e->tag = csio->tag_action;
13717b13bc96SSascha Wildner }
13727b13bc96SSascha Wildner
13737b13bc96SSascha Wildner e->context = pvscsi_hcb_to_context(sc, hcb);
13747b13bc96SSascha Wildner hcb->e = e;
13757b13bc96SSascha Wildner
13767b13bc96SSascha Wildner DEBUG_PRINTF(3, sc->dev,
13777b13bc96SSascha Wildner " queuing command %02x context %llx\n", e->cdb[0],
13787b13bc96SSascha Wildner (unsigned long long)e->context);
13797b13bc96SSascha Wildner bus_dmamap_load_ccb(sc->buffer_dmat, hcb->dma_map, ccb,
13807b13bc96SSascha Wildner pvscsi_execute_ccb, hcb, 0);
13817b13bc96SSascha Wildner break;
13827b13bc96SSascha Wildner
13837b13bc96SSascha Wildner finish_ccb:
13847b13bc96SSascha Wildner if (hcb != NULL) {
13857b13bc96SSascha Wildner pvscsi_hcb_put(sc, hcb);
13867b13bc96SSascha Wildner }
13877b13bc96SSascha Wildner xpt_done(ccb);
13887b13bc96SSascha Wildner } break;
13897b13bc96SSascha Wildner case XPT_ABORT:
13907b13bc96SSascha Wildner {
13917b13bc96SSascha Wildner struct pvscsi_hcb *abort_hcb;
13927b13bc96SSascha Wildner union ccb *abort_ccb;
13937b13bc96SSascha Wildner
13947b13bc96SSascha Wildner abort_ccb = ccb->cab.abort_ccb;
13957b13bc96SSascha Wildner abort_hcb = abort_ccb->ccb_h.ccb_pvscsi_hcb;
13967b13bc96SSascha Wildner
13977b13bc96SSascha Wildner if (abort_hcb->ccb != NULL && abort_hcb->ccb == abort_ccb) {
13987b13bc96SSascha Wildner if (abort_ccb->ccb_h.func_code == XPT_SCSI_IO) {
13997b13bc96SSascha Wildner pvscsi_abort(sc, ccb_h->target_id, abort_ccb);
14007b13bc96SSascha Wildner ccb_h->status = CAM_REQ_CMP;
14017b13bc96SSascha Wildner } else {
14027b13bc96SSascha Wildner ccb_h->status = CAM_UA_ABORT;
14037b13bc96SSascha Wildner }
14047b13bc96SSascha Wildner } else {
14057b13bc96SSascha Wildner device_printf(sc->dev,
14067b13bc96SSascha Wildner "Could not find hcb for ccb %p (tgt %u)\n",
14077b13bc96SSascha Wildner ccb, ccb_h->target_id);
14087b13bc96SSascha Wildner ccb_h->status = CAM_REQ_CMP;
14097b13bc96SSascha Wildner }
14107b13bc96SSascha Wildner xpt_done(ccb);
14117b13bc96SSascha Wildner } break;
14127b13bc96SSascha Wildner case XPT_RESET_DEV:
14137b13bc96SSascha Wildner {
14147b13bc96SSascha Wildner pvscsi_device_reset(sc, ccb_h->target_id);
14157b13bc96SSascha Wildner ccb_h->status = CAM_REQ_CMP;
14167b13bc96SSascha Wildner xpt_done(ccb);
14177b13bc96SSascha Wildner } break;
14187b13bc96SSascha Wildner case XPT_RESET_BUS:
14197b13bc96SSascha Wildner {
14207b13bc96SSascha Wildner pvscsi_bus_reset(sc);
14217b13bc96SSascha Wildner ccb_h->status = CAM_REQ_CMP;
14227b13bc96SSascha Wildner xpt_done(ccb);
14237b13bc96SSascha Wildner } break;
14247b13bc96SSascha Wildner case XPT_PATH_INQ:
14257b13bc96SSascha Wildner {
14267b13bc96SSascha Wildner struct ccb_pathinq *cpi;
14277b13bc96SSascha Wildner
14287b13bc96SSascha Wildner cpi = &ccb->cpi;
14297b13bc96SSascha Wildner
14307b13bc96SSascha Wildner cpi->version_num = 1;
14317b13bc96SSascha Wildner cpi->hba_inquiry = PI_TAG_ABLE;
14327b13bc96SSascha Wildner cpi->target_sprt = 0;
14331c0b11abSSascha Wildner cpi->hba_misc = PIM_NOBUSRESET;
14347b13bc96SSascha Wildner cpi->hba_eng_cnt = 0;
14357b13bc96SSascha Wildner /* cpi->vuhba_flags = 0; */
14367b13bc96SSascha Wildner cpi->max_target = sc->max_targets;
14377b13bc96SSascha Wildner cpi->max_lun = 0;
14387b13bc96SSascha Wildner cpi->async_flags = 0;
14397b13bc96SSascha Wildner cpi->hpath_id = 0;
14407b13bc96SSascha Wildner cpi->unit_number = cam_sim_unit(sim);
14417b13bc96SSascha Wildner cpi->bus_id = cam_sim_bus(sim);
14427b13bc96SSascha Wildner cpi->initiator_id = 7;
14437b13bc96SSascha Wildner cpi->base_transfer_speed = 750000;
14447b13bc96SSascha Wildner strlcpy(cpi->sim_vid, "VMware", SIM_IDLEN);
14457b13bc96SSascha Wildner strlcpy(cpi->hba_vid, "VMware", HBA_IDLEN);
14467b13bc96SSascha Wildner strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
14477b13bc96SSascha Wildner /* Limit I/O to 256k since we can't do 512k unaligned I/O */
14487b13bc96SSascha Wildner cpi->maxio = (PVSCSI_MAX_SG_ENTRIES_PER_SEGMENT / 2) * PAGE_SIZE;
14497b13bc96SSascha Wildner cpi->protocol = PROTO_SCSI;
14507b13bc96SSascha Wildner cpi->protocol_version = SCSI_REV_SPC2;
14517b13bc96SSascha Wildner cpi->transport = XPORT_SAS;
14527b13bc96SSascha Wildner cpi->transport_version = 0;
14537b13bc96SSascha Wildner
14547b13bc96SSascha Wildner ccb_h->status = CAM_REQ_CMP;
14557b13bc96SSascha Wildner xpt_done(ccb);
14567b13bc96SSascha Wildner } break;
14577b13bc96SSascha Wildner case XPT_GET_TRAN_SETTINGS:
14587b13bc96SSascha Wildner {
14597b13bc96SSascha Wildner struct ccb_trans_settings *cts;
14607b13bc96SSascha Wildner
14617b13bc96SSascha Wildner cts = &ccb->cts;
14627b13bc96SSascha Wildner
14637b13bc96SSascha Wildner cts->protocol = PROTO_SCSI;
14647b13bc96SSascha Wildner cts->protocol_version = SCSI_REV_SPC2;
14657b13bc96SSascha Wildner cts->transport = XPORT_SAS;
14667b13bc96SSascha Wildner cts->transport_version = 0;
14677b13bc96SSascha Wildner
14687b13bc96SSascha Wildner cts->proto_specific.scsi.flags = CTS_SCSI_FLAGS_TAG_ENB;
14697b13bc96SSascha Wildner cts->proto_specific.scsi.valid = CTS_SCSI_VALID_TQ;
14707b13bc96SSascha Wildner
14717b13bc96SSascha Wildner ccb_h->status = CAM_REQ_CMP;
14727b13bc96SSascha Wildner xpt_done(ccb);
14737b13bc96SSascha Wildner } break;
14747b13bc96SSascha Wildner case XPT_CALC_GEOMETRY:
14757b13bc96SSascha Wildner {
14767b13bc96SSascha Wildner cam_calc_geometry(&ccb->ccg, 1);
14777b13bc96SSascha Wildner xpt_done(ccb);
14787b13bc96SSascha Wildner } break;
14797b13bc96SSascha Wildner default:
14807b13bc96SSascha Wildner ccb_h->status = CAM_REQ_INVALID;
14817b13bc96SSascha Wildner xpt_done(ccb);
14827b13bc96SSascha Wildner break;
14837b13bc96SSascha Wildner }
14847b13bc96SSascha Wildner }
14857b13bc96SSascha Wildner
14867b13bc96SSascha Wildner static void
pvscsi_free_interrupts(struct pvscsi_softc * sc)14877b13bc96SSascha Wildner pvscsi_free_interrupts(struct pvscsi_softc *sc)
14887b13bc96SSascha Wildner {
14897b13bc96SSascha Wildner
14907b13bc96SSascha Wildner if (sc->irq_handler != NULL) {
14917b13bc96SSascha Wildner bus_teardown_intr(sc->dev, sc->irq_res, sc->irq_handler);
14927b13bc96SSascha Wildner }
14937b13bc96SSascha Wildner if (sc->irq_res != NULL) {
14947b13bc96SSascha Wildner bus_release_resource(sc->dev, SYS_RES_IRQ, sc->irq_id,
14957b13bc96SSascha Wildner sc->irq_res);
14967b13bc96SSascha Wildner }
14977b13bc96SSascha Wildner if (sc->use_msi_or_msix) {
14987b13bc96SSascha Wildner pci_release_msi(sc->dev);
14997b13bc96SSascha Wildner }
15007b13bc96SSascha Wildner }
15017b13bc96SSascha Wildner
15027b13bc96SSascha Wildner static int
pvscsi_setup_interrupts(struct pvscsi_softc * sc)15037b13bc96SSascha Wildner pvscsi_setup_interrupts(struct pvscsi_softc *sc)
15047b13bc96SSascha Wildner {
15057b13bc96SSascha Wildner int error;
15067b13bc96SSascha Wildner int flags;
15071c0b11abSSascha Wildner #if 0 /* XXX swildner: MSI-X support */
15087b13bc96SSascha Wildner int use_msix;
15091c0b11abSSascha Wildner #endif
15107b13bc96SSascha Wildner int use_msi;
15111c0b11abSSascha Wildner #if 0 /* XXX swildner: MSI-X support */
15127b13bc96SSascha Wildner int count;
15131c0b11abSSascha Wildner #endif
15147b13bc96SSascha Wildner
15157b13bc96SSascha Wildner sc->use_msi_or_msix = 0;
15167b13bc96SSascha Wildner
15171c0b11abSSascha Wildner #if 0 /* XXX swildner: MSI-X support */
15187b13bc96SSascha Wildner use_msix = pvscsi_get_tunable(sc, "use_msix", pvscsi_use_msix);
15191c0b11abSSascha Wildner #endif
15207b13bc96SSascha Wildner use_msi = pvscsi_get_tunable(sc, "use_msi", pvscsi_use_msi);
15217b13bc96SSascha Wildner
15221c0b11abSSascha Wildner #if 0 /* XXX swildner: MSI-X support */
15237b13bc96SSascha Wildner if (use_msix && pci_msix_count(sc->dev) > 0) {
15247b13bc96SSascha Wildner count = 1;
15257b13bc96SSascha Wildner if (pci_alloc_msix(sc->dev, &count) == 0 && count == 1) {
15267b13bc96SSascha Wildner sc->use_msi_or_msix = 1;
15277b13bc96SSascha Wildner device_printf(sc->dev, "Interrupt: MSI-X\n");
15287b13bc96SSascha Wildner } else {
15297b13bc96SSascha Wildner pci_release_msi(sc->dev);
15307b13bc96SSascha Wildner }
15317b13bc96SSascha Wildner }
15321c0b11abSSascha Wildner #endif
15337b13bc96SSascha Wildner
15341c0b11abSSascha Wildner sc->irq_id = 0;
15351c0b11abSSascha Wildner sc->irq_type = pci_alloc_1intr(sc->dev, use_msi, &sc->irq_id,
15361c0b11abSSascha Wildner &flags);
15371c0b11abSSascha Wildner if (use_msi) {
15387b13bc96SSascha Wildner sc->use_msi_or_msix = 1;
15397b13bc96SSascha Wildner device_printf(sc->dev, "Interrupt: MSI\n");
15407b13bc96SSascha Wildner } else {
15417b13bc96SSascha Wildner device_printf(sc->dev, "Interrupt: INT\n");
15427b13bc96SSascha Wildner }
15437b13bc96SSascha Wildner
15447b13bc96SSascha Wildner sc->irq_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, &sc->irq_id,
15457b13bc96SSascha Wildner flags);
15467b13bc96SSascha Wildner if (sc->irq_res == NULL) {
15477b13bc96SSascha Wildner device_printf(sc->dev, "IRQ allocation failed\n");
15487b13bc96SSascha Wildner if (sc->use_msi_or_msix) {
15497b13bc96SSascha Wildner pci_release_msi(sc->dev);
15507b13bc96SSascha Wildner }
15517b13bc96SSascha Wildner return (ENXIO);
15527b13bc96SSascha Wildner }
15537b13bc96SSascha Wildner
15547b13bc96SSascha Wildner error = bus_setup_intr(sc->dev, sc->irq_res,
15551c0b11abSSascha Wildner INTR_MPSAFE, pvscsi_intr, sc,
15561c0b11abSSascha Wildner &sc->irq_handler, NULL);
15577b13bc96SSascha Wildner if (error) {
15587b13bc96SSascha Wildner device_printf(sc->dev, "IRQ handler setup failed\n");
15597b13bc96SSascha Wildner pvscsi_free_interrupts(sc);
15607b13bc96SSascha Wildner return (error);
15617b13bc96SSascha Wildner }
15627b13bc96SSascha Wildner
15637b13bc96SSascha Wildner return (0);
15647b13bc96SSascha Wildner }
15657b13bc96SSascha Wildner
15667b13bc96SSascha Wildner static void
pvscsi_free_all(struct pvscsi_softc * sc)15677b13bc96SSascha Wildner pvscsi_free_all(struct pvscsi_softc *sc)
15687b13bc96SSascha Wildner {
15697b13bc96SSascha Wildner
15707b13bc96SSascha Wildner if (sc->sim) {
15711c0b11abSSascha Wildner int32_t status;
15727b13bc96SSascha Wildner
15737b13bc96SSascha Wildner if (sc->bus_path) {
15747b13bc96SSascha Wildner xpt_free_path(sc->bus_path);
15757b13bc96SSascha Wildner }
15767b13bc96SSascha Wildner
15771c0b11abSSascha Wildner status = xpt_bus_deregister(cam_sim_path(sc->sim));
15781c0b11abSSascha Wildner if (status != CAM_REQ_CMP) {
15797b13bc96SSascha Wildner device_printf(sc->dev,
15801c0b11abSSascha Wildner "Error deregistering bus, status=%d\n", status);
15817b13bc96SSascha Wildner }
15827b13bc96SSascha Wildner
15831c0b11abSSascha Wildner cam_sim_free(sc->sim);
15847b13bc96SSascha Wildner }
15857b13bc96SSascha Wildner
15867b13bc96SSascha Wildner pvscsi_dma_free_per_hcb(sc, sc->hcb_cnt);
15877b13bc96SSascha Wildner
15887b13bc96SSascha Wildner if (sc->hcbs) {
15891c0b11abSSascha Wildner kfree(sc->hcbs, M_PVSCSI);
15907b13bc96SSascha Wildner }
15917b13bc96SSascha Wildner
15927b13bc96SSascha Wildner pvscsi_free_rings(sc);
15937b13bc96SSascha Wildner
15947b13bc96SSascha Wildner pvscsi_free_interrupts(sc);
15957b13bc96SSascha Wildner
15967b13bc96SSascha Wildner if (sc->buffer_dmat != NULL) {
15977b13bc96SSascha Wildner bus_dma_tag_destroy(sc->buffer_dmat);
15987b13bc96SSascha Wildner }
15997b13bc96SSascha Wildner
16007b13bc96SSascha Wildner if (sc->parent_dmat != NULL) {
16017b13bc96SSascha Wildner bus_dma_tag_destroy(sc->parent_dmat);
16027b13bc96SSascha Wildner }
16037b13bc96SSascha Wildner
16047b13bc96SSascha Wildner if (sc->mm_res != NULL) {
16057b13bc96SSascha Wildner bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->mm_rid,
16067b13bc96SSascha Wildner sc->mm_res);
16077b13bc96SSascha Wildner }
16087b13bc96SSascha Wildner }
16097b13bc96SSascha Wildner
16107b13bc96SSascha Wildner static int
pvscsi_attach(device_t dev)16117b13bc96SSascha Wildner pvscsi_attach(device_t dev)
16127b13bc96SSascha Wildner {
16137b13bc96SSascha Wildner struct pvscsi_softc *sc;
16147b13bc96SSascha Wildner int rid;
16157b13bc96SSascha Wildner int barid;
16167b13bc96SSascha Wildner int error;
16177b13bc96SSascha Wildner int max_queue_depth;
16187b13bc96SSascha Wildner int adapter_queue_size;
16197b13bc96SSascha Wildner struct cam_devq *devq;
16207b13bc96SSascha Wildner
16217b13bc96SSascha Wildner sc = device_get_softc(dev);
16227b13bc96SSascha Wildner sc->dev = dev;
16237b13bc96SSascha Wildner
16241c0b11abSSascha Wildner lockinit(&sc->lock, "pvscsi", 0, LK_CANRECURSE);
16257b13bc96SSascha Wildner
16267b13bc96SSascha Wildner pci_enable_busmaster(dev);
16277b13bc96SSascha Wildner
16287b13bc96SSascha Wildner sc->mm_rid = -1;
16297b13bc96SSascha Wildner for (barid = 0; barid <= PCIR_MAX_BAR_0; ++barid) {
16307b13bc96SSascha Wildner rid = PCIR_BAR(barid);
16317b13bc96SSascha Wildner
16327b13bc96SSascha Wildner sc->mm_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
16337b13bc96SSascha Wildner RF_ACTIVE);
16347b13bc96SSascha Wildner if (sc->mm_res != NULL) {
16357b13bc96SSascha Wildner sc->mm_rid = rid;
16367b13bc96SSascha Wildner break;
16377b13bc96SSascha Wildner }
16387b13bc96SSascha Wildner }
16397b13bc96SSascha Wildner
16407b13bc96SSascha Wildner if (sc->mm_res == NULL) {
16417b13bc96SSascha Wildner device_printf(dev, "could not map device memory\n");
16427b13bc96SSascha Wildner return (ENXIO);
16437b13bc96SSascha Wildner }
16447b13bc96SSascha Wildner
16457b13bc96SSascha Wildner error = bus_dma_tag_create(bus_get_dma_tag(dev), 1, 0,
1646*030b0c8cSMichael Neumann BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, BUS_SPACE_MAXSIZE,
16471c0b11abSSascha Wildner BUS_SPACE_UNRESTRICTED, BUS_SPACE_MAXSIZE, 0,
16487b13bc96SSascha Wildner &sc->parent_dmat);
16497b13bc96SSascha Wildner if (error) {
16507b13bc96SSascha Wildner device_printf(dev, "parent dma tag create failure, error %d\n",
16517b13bc96SSascha Wildner error);
16527b13bc96SSascha Wildner pvscsi_free_all(sc);
16537b13bc96SSascha Wildner return (ENXIO);
16547b13bc96SSascha Wildner }
16557b13bc96SSascha Wildner
16567b13bc96SSascha Wildner error = bus_dma_tag_create(sc->parent_dmat, 1, 0,
1657*030b0c8cSMichael Neumann BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR,
16587b13bc96SSascha Wildner PVSCSI_MAX_SG_ENTRIES_PER_SEGMENT * PAGE_SIZE,
16597b13bc96SSascha Wildner PVSCSI_MAX_SG_ENTRIES_PER_SEGMENT, PAGE_SIZE, BUS_DMA_ALLOCNOW,
16601c0b11abSSascha Wildner &sc->buffer_dmat);
16617b13bc96SSascha Wildner if (error) {
16627b13bc96SSascha Wildner device_printf(dev, "parent dma tag create failure, error %d\n",
16637b13bc96SSascha Wildner error);
16647b13bc96SSascha Wildner pvscsi_free_all(sc);
16657b13bc96SSascha Wildner return (ENXIO);
16667b13bc96SSascha Wildner }
16677b13bc96SSascha Wildner
16687b13bc96SSascha Wildner error = pvscsi_setup_interrupts(sc);
16697b13bc96SSascha Wildner if (error) {
16707b13bc96SSascha Wildner device_printf(dev, "Interrupt setup failed\n");
16717b13bc96SSascha Wildner pvscsi_free_all(sc);
16727b13bc96SSascha Wildner return (error);
16737b13bc96SSascha Wildner }
16747b13bc96SSascha Wildner
16757b13bc96SSascha Wildner sc->max_targets = pvscsi_get_max_targets(sc);
16767b13bc96SSascha Wildner
16777b13bc96SSascha Wildner sc->use_msg = pvscsi_get_tunable(sc, "use_msg", pvscsi_use_msg) &&
16787b13bc96SSascha Wildner pvscsi_hw_supports_msg(sc);
16797b13bc96SSascha Wildner sc->msg_ring_num_pages = sc->use_msg ? 1 : 0;
16807b13bc96SSascha Wildner
16817b13bc96SSascha Wildner sc->req_ring_num_pages = pvscsi_get_tunable(sc, "request_ring_pages",
16827b13bc96SSascha Wildner pvscsi_request_ring_pages);
16837b13bc96SSascha Wildner if (sc->req_ring_num_pages <= 0) {
16847b13bc96SSascha Wildner if (sc->max_targets <= 16) {
16857b13bc96SSascha Wildner sc->req_ring_num_pages =
16867b13bc96SSascha Wildner PVSCSI_DEFAULT_NUM_PAGES_REQ_RING;
16877b13bc96SSascha Wildner } else {
16887b13bc96SSascha Wildner sc->req_ring_num_pages = PVSCSI_MAX_NUM_PAGES_REQ_RING;
16897b13bc96SSascha Wildner }
16907b13bc96SSascha Wildner } else if (sc->req_ring_num_pages > PVSCSI_MAX_NUM_PAGES_REQ_RING) {
16917b13bc96SSascha Wildner sc->req_ring_num_pages = PVSCSI_MAX_NUM_PAGES_REQ_RING;
16927b13bc96SSascha Wildner }
16937b13bc96SSascha Wildner sc->cmp_ring_num_pages = sc->req_ring_num_pages;
16947b13bc96SSascha Wildner
16957b13bc96SSascha Wildner max_queue_depth = pvscsi_get_tunable(sc, "max_queue_depth",
16967b13bc96SSascha Wildner pvscsi_max_queue_depth);
16977b13bc96SSascha Wildner
16987b13bc96SSascha Wildner adapter_queue_size = (sc->req_ring_num_pages * PAGE_SIZE) /
16997b13bc96SSascha Wildner sizeof(struct pvscsi_ring_req_desc);
17007b13bc96SSascha Wildner if (max_queue_depth > 0) {
17017b13bc96SSascha Wildner adapter_queue_size = MIN(adapter_queue_size, max_queue_depth);
17027b13bc96SSascha Wildner }
17037b13bc96SSascha Wildner adapter_queue_size = MIN(adapter_queue_size,
17047b13bc96SSascha Wildner PVSCSI_MAX_REQ_QUEUE_DEPTH);
17057b13bc96SSascha Wildner
17067b13bc96SSascha Wildner device_printf(sc->dev, "Use Msg: %d\n", sc->use_msg);
17077b13bc96SSascha Wildner device_printf(sc->dev, "REQ num pages: %d\n", sc->req_ring_num_pages);
17087b13bc96SSascha Wildner device_printf(sc->dev, "CMP num pages: %d\n", sc->cmp_ring_num_pages);
17097b13bc96SSascha Wildner device_printf(sc->dev, "MSG num pages: %d\n", sc->msg_ring_num_pages);
17107b13bc96SSascha Wildner device_printf(sc->dev, "Queue size: %d\n", adapter_queue_size);
17117b13bc96SSascha Wildner
17127b13bc96SSascha Wildner if (pvscsi_allocate_rings(sc)) {
17137b13bc96SSascha Wildner device_printf(dev, "ring allocation failed\n");
17147b13bc96SSascha Wildner pvscsi_free_all(sc);
17157b13bc96SSascha Wildner return (ENXIO);
17167b13bc96SSascha Wildner }
17177b13bc96SSascha Wildner
17187b13bc96SSascha Wildner sc->hcb_cnt = adapter_queue_size;
17191c0b11abSSascha Wildner sc->hcbs = kmalloc(sc->hcb_cnt * sizeof(*sc->hcbs), M_PVSCSI,
17207b13bc96SSascha Wildner M_NOWAIT | M_ZERO);
17217b13bc96SSascha Wildner if (sc->hcbs == NULL) {
17227b13bc96SSascha Wildner device_printf(dev, "error allocating hcb array\n");
17237b13bc96SSascha Wildner pvscsi_free_all(sc);
17247b13bc96SSascha Wildner return (ENXIO);
17257b13bc96SSascha Wildner }
17267b13bc96SSascha Wildner
17277b13bc96SSascha Wildner if (pvscsi_dma_alloc_per_hcb(sc)) {
17287b13bc96SSascha Wildner device_printf(dev, "error allocating per hcb dma memory\n");
17297b13bc96SSascha Wildner pvscsi_free_all(sc);
17307b13bc96SSascha Wildner return (ENXIO);
17317b13bc96SSascha Wildner }
17327b13bc96SSascha Wildner
17337b13bc96SSascha Wildner pvscsi_adapter_reset(sc);
17347b13bc96SSascha Wildner
17357b13bc96SSascha Wildner devq = cam_simq_alloc(adapter_queue_size);
17367b13bc96SSascha Wildner if (devq == NULL) {
17377b13bc96SSascha Wildner device_printf(dev, "cam devq alloc failed\n");
17387b13bc96SSascha Wildner pvscsi_free_all(sc);
17397b13bc96SSascha Wildner return (ENXIO);
17407b13bc96SSascha Wildner }
17417b13bc96SSascha Wildner
17427b13bc96SSascha Wildner sc->sim = cam_sim_alloc(pvscsi_action, pvscsi_poll, "pvscsi", sc,
17437b13bc96SSascha Wildner device_get_unit(dev), &sc->lock, 1, adapter_queue_size, devq);
17441c0b11abSSascha Wildner cam_simq_release(devq);
17457b13bc96SSascha Wildner if (sc->sim == NULL) {
17467b13bc96SSascha Wildner device_printf(dev, "cam sim alloc failed\n");
17477b13bc96SSascha Wildner pvscsi_free_all(sc);
17487b13bc96SSascha Wildner return (ENXIO);
17497b13bc96SSascha Wildner }
17507b13bc96SSascha Wildner
17511c0b11abSSascha Wildner lockmgr(&sc->lock, LK_EXCLUSIVE);
17527b13bc96SSascha Wildner
17531c0b11abSSascha Wildner if (xpt_bus_register(sc->sim, 0) != CAM_SUCCESS) {
17547b13bc96SSascha Wildner device_printf(dev, "xpt bus register failed\n");
17557b13bc96SSascha Wildner pvscsi_free_all(sc);
17561c0b11abSSascha Wildner lockmgr(&sc->lock, LK_RELEASE);
17577b13bc96SSascha Wildner return (ENXIO);
17587b13bc96SSascha Wildner }
17597b13bc96SSascha Wildner
17607b13bc96SSascha Wildner if (xpt_create_path(&sc->bus_path, NULL, cam_sim_path(sc->sim),
17617b13bc96SSascha Wildner CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
17627b13bc96SSascha Wildner device_printf(dev, "xpt create path failed\n");
17637b13bc96SSascha Wildner pvscsi_free_all(sc);
17641c0b11abSSascha Wildner lockmgr(&sc->lock, LK_RELEASE);
17657b13bc96SSascha Wildner return (ENXIO);
17667b13bc96SSascha Wildner }
17677b13bc96SSascha Wildner
17687b13bc96SSascha Wildner pvscsi_setup_rings(sc);
17697b13bc96SSascha Wildner if (sc->use_msg) {
17707b13bc96SSascha Wildner pvscsi_setup_msg_ring(sc);
17717b13bc96SSascha Wildner }
17727b13bc96SSascha Wildner
17737b13bc96SSascha Wildner sc->use_req_call_threshold = pvscsi_setup_req_call(sc, 1);
17747b13bc96SSascha Wildner
17757b13bc96SSascha Wildner pvscsi_intr_enable(sc);
17767b13bc96SSascha Wildner
17771c0b11abSSascha Wildner lockmgr(&sc->lock, LK_RELEASE);
17787b13bc96SSascha Wildner
17797b13bc96SSascha Wildner return (0);
17807b13bc96SSascha Wildner }
17817b13bc96SSascha Wildner
17827b13bc96SSascha Wildner static int
pvscsi_detach(device_t dev)17837b13bc96SSascha Wildner pvscsi_detach(device_t dev)
17847b13bc96SSascha Wildner {
17857b13bc96SSascha Wildner struct pvscsi_softc *sc;
17867b13bc96SSascha Wildner
17877b13bc96SSascha Wildner sc = device_get_softc(dev);
17887b13bc96SSascha Wildner
17897b13bc96SSascha Wildner pvscsi_intr_disable(sc);
17907b13bc96SSascha Wildner pvscsi_adapter_reset(sc);
17917b13bc96SSascha Wildner
17921c0b11abSSascha Wildner lockmgr(&sc->lock, LK_EXCLUSIVE);
17937b13bc96SSascha Wildner pvscsi_free_all(sc);
17941c0b11abSSascha Wildner lockmgr(&sc->lock, LK_RELEASE);
17957b13bc96SSascha Wildner
17961c0b11abSSascha Wildner lockuninit(&sc->lock);
17977b13bc96SSascha Wildner
17987b13bc96SSascha Wildner return (0);
17997b13bc96SSascha Wildner }
18007b13bc96SSascha Wildner
18017b13bc96SSascha Wildner static device_method_t pvscsi_methods[] = {
18027b13bc96SSascha Wildner DEVMETHOD(device_probe, pvscsi_probe),
18037b13bc96SSascha Wildner DEVMETHOD(device_shutdown, pvscsi_shutdown),
18047b13bc96SSascha Wildner DEVMETHOD(device_attach, pvscsi_attach),
18057b13bc96SSascha Wildner DEVMETHOD(device_detach, pvscsi_detach),
18067b13bc96SSascha Wildner DEVMETHOD_END
18077b13bc96SSascha Wildner };
18087b13bc96SSascha Wildner
18097b13bc96SSascha Wildner static driver_t pvscsi_driver = {
18107b13bc96SSascha Wildner "pvscsi", pvscsi_methods, sizeof(struct pvscsi_softc)
18117b13bc96SSascha Wildner };
18127b13bc96SSascha Wildner
18131c0b11abSSascha Wildner static devclass_t pvscsi_devclass;
18141c0b11abSSascha Wildner DRIVER_MODULE(pvscsi, pci, pvscsi_driver, pvscsi_devclass, NULL, NULL);
18151c0b11abSSascha Wildner MODULE_VERSION(pvscsi, 1);
18167b13bc96SSascha Wildner
18177b13bc96SSascha Wildner MODULE_DEPEND(pvscsi, pci, 1, 1, 1);
18187b13bc96SSascha Wildner MODULE_DEPEND(pvscsi, cam, 1, 1, 1);
1819