xref: /dragonfly/sys/dev/virtual/vmware/pvscsi/pvscsi.c (revision 030b0c8c)
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