1f52228b8SJoe Beteta /* 2f52228b8SJoe Beteta * 3f52228b8SJoe Beteta * skd.c: Solaris 11/10 Driver for sTec, Inc. S112x PCIe SSD card 4f52228b8SJoe Beteta * 5f52228b8SJoe Beteta * Solaris driver is based on the Linux driver authored by: 6f52228b8SJoe Beteta * 7f52228b8SJoe Beteta * Authors/Alphabetical: Dragan Stancevic <dstancevic@stec-inc.com> 8f52228b8SJoe Beteta * Gordon Waidhofer <gwaidhofer@stec-inc.com> 9f52228b8SJoe Beteta * John Hamilton <jhamilton@stec-inc.com> 10f52228b8SJoe Beteta */ 11f52228b8SJoe Beteta 12f52228b8SJoe Beteta /* 13f52228b8SJoe Beteta * This file and its contents are supplied under the terms of the 14f52228b8SJoe Beteta * Common Development and Distribution License ("CDDL"), version 1.0. 15f52228b8SJoe Beteta * You may only use this file in accordance with the terms of version 16f52228b8SJoe Beteta * 1.0 of the CDDL. 17f52228b8SJoe Beteta * 18f52228b8SJoe Beteta * A full copy of the text of the CDDL should have accompanied this 19f52228b8SJoe Beteta * source. A copy of the CDDL is also available via the Internet at 20f52228b8SJoe Beteta * http://www.illumos.org/license/CDDL. 21f52228b8SJoe Beteta */ 22f52228b8SJoe Beteta 23f52228b8SJoe Beteta /* 24f52228b8SJoe Beteta * Copyright 2013 STEC, Inc. All rights reserved. 25510a6847SHans Rosenfeld * Copyright 2015 Nexenta Systems, Inc. All rights reserved. 26f52228b8SJoe Beteta */ 27f52228b8SJoe Beteta 28f52228b8SJoe Beteta #include <sys/types.h> 29f52228b8SJoe Beteta #include <sys/stream.h> 30f52228b8SJoe Beteta #include <sys/cmn_err.h> 31f52228b8SJoe Beteta #include <sys/kmem.h> 32f52228b8SJoe Beteta #include <sys/file.h> 33f52228b8SJoe Beteta #include <sys/buf.h> 34f52228b8SJoe Beteta #include <sys/uio.h> 35f52228b8SJoe Beteta #include <sys/cred.h> 36f52228b8SJoe Beteta #include <sys/modctl.h> 37f52228b8SJoe Beteta #include <sys/debug.h> 38f52228b8SJoe Beteta #include <sys/modctl.h> 39f52228b8SJoe Beteta #include <sys/list.h> 40f52228b8SJoe Beteta #include <sys/sysmacros.h> 41f52228b8SJoe Beteta #include <sys/errno.h> 42f52228b8SJoe Beteta #include <sys/pcie.h> 43f52228b8SJoe Beteta #include <sys/pci.h> 44f52228b8SJoe Beteta #include <sys/ddi.h> 45f52228b8SJoe Beteta #include <sys/dditypes.h> 46f52228b8SJoe Beteta #include <sys/sunddi.h> 47f52228b8SJoe Beteta #include <sys/atomic.h> 48f52228b8SJoe Beteta #include <sys/mutex.h> 49f52228b8SJoe Beteta #include <sys/param.h> 50f52228b8SJoe Beteta #include <sys/devops.h> 51f52228b8SJoe Beteta #include <sys/blkdev.h> 52f52228b8SJoe Beteta #include <sys/queue.h> 53*bef9e21aSHans Rosenfeld #include <sys/scsi/impl/inquiry.h> 54f52228b8SJoe Beteta 55f52228b8SJoe Beteta #include "skd_s1120.h" 56f52228b8SJoe Beteta #include "skd.h" 57f52228b8SJoe Beteta 58f52228b8SJoe Beteta int skd_dbg_level = 0; 59f52228b8SJoe Beteta 60f52228b8SJoe Beteta void *skd_state = NULL; 61f52228b8SJoe Beteta int skd_disable_msi = 0; 62f52228b8SJoe Beteta int skd_disable_msix = 0; 63f52228b8SJoe Beteta 64f52228b8SJoe Beteta /* Initialized in _init() and tunable, see _init(). */ 65f52228b8SJoe Beteta clock_t skd_timer_ticks; 66f52228b8SJoe Beteta 67f52228b8SJoe Beteta /* I/O DMA attributes structures. */ 68f52228b8SJoe Beteta static ddi_dma_attr_t skd_64bit_io_dma_attr = { 69f52228b8SJoe Beteta DMA_ATTR_V0, /* dma_attr_version */ 70f52228b8SJoe Beteta SKD_DMA_LOW_ADDRESS, /* low DMA address range */ 71f52228b8SJoe Beteta SKD_DMA_HIGH_64BIT_ADDRESS, /* high DMA address range */ 72f52228b8SJoe Beteta SKD_DMA_XFER_COUNTER, /* DMA counter register */ 73f52228b8SJoe Beteta SKD_DMA_ADDRESS_ALIGNMENT, /* DMA address alignment */ 74f52228b8SJoe Beteta SKD_DMA_BURSTSIZES, /* DMA burstsizes */ 75f52228b8SJoe Beteta SKD_DMA_MIN_XFER_SIZE, /* min effective DMA size */ 76f52228b8SJoe Beteta SKD_DMA_MAX_XFER_SIZE, /* max DMA xfer size */ 77f52228b8SJoe Beteta SKD_DMA_SEGMENT_BOUNDARY, /* segment boundary */ 78f52228b8SJoe Beteta SKD_DMA_SG_LIST_LENGTH, /* s/g list length */ 79f52228b8SJoe Beteta SKD_DMA_GRANULARITY, /* granularity of device */ 80f52228b8SJoe Beteta SKD_DMA_XFER_FLAGS /* DMA transfer flags */ 81f52228b8SJoe Beteta }; 82f52228b8SJoe Beteta 83f52228b8SJoe Beteta int skd_isr_type = -1; 84f52228b8SJoe Beteta 85f52228b8SJoe Beteta #define SKD_MAX_QUEUE_DEPTH 255 86f52228b8SJoe Beteta #define SKD_MAX_QUEUE_DEPTH_DEFAULT 64 87f52228b8SJoe Beteta int skd_max_queue_depth = SKD_MAX_QUEUE_DEPTH_DEFAULT; 88f52228b8SJoe Beteta 89f52228b8SJoe Beteta #define SKD_MAX_REQ_PER_MSG 14 90f52228b8SJoe Beteta #define SKD_MAX_REQ_PER_MSG_DEFAULT 1 91f52228b8SJoe Beteta int skd_max_req_per_msg = SKD_MAX_REQ_PER_MSG_DEFAULT; 92f52228b8SJoe Beteta 93f52228b8SJoe Beteta #define SKD_MAX_N_SG_PER_REQ 4096 94f52228b8SJoe Beteta int skd_sgs_per_request = SKD_N_SG_PER_REQ_DEFAULT; 95f52228b8SJoe Beteta 96f52228b8SJoe Beteta static int skd_sys_quiesce_dev(dev_info_t *); 97f52228b8SJoe Beteta static int skd_quiesce_dev(skd_device_t *); 98f52228b8SJoe Beteta static int skd_list_skmsg(skd_device_t *, int); 99f52228b8SJoe Beteta static int skd_list_skreq(skd_device_t *, int); 100f52228b8SJoe Beteta static int skd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 101f52228b8SJoe Beteta static int skd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 102f52228b8SJoe Beteta static int skd_format_internal_skspcl(struct skd_device *skdev); 103f52228b8SJoe Beteta static void skd_start(skd_device_t *); 104f52228b8SJoe Beteta static void skd_destroy_mutex(skd_device_t *skdev); 105f52228b8SJoe Beteta static void skd_enable_interrupts(struct skd_device *); 106f52228b8SJoe Beteta static void skd_request_fn_not_online(skd_device_t *skdev); 107f52228b8SJoe Beteta static void skd_send_internal_skspcl(struct skd_device *, 108f52228b8SJoe Beteta struct skd_special_context *, uint8_t); 109f52228b8SJoe Beteta static void skd_queue(skd_device_t *, skd_buf_private_t *); 110f52228b8SJoe Beteta static void *skd_alloc_dma_mem(skd_device_t *, dma_mem_t *, uint8_t); 111f52228b8SJoe Beteta static void skd_release_intr(skd_device_t *skdev); 112f52228b8SJoe Beteta static void skd_isr_fwstate(struct skd_device *skdev); 113f52228b8SJoe Beteta static void skd_isr_msg_from_dev(struct skd_device *skdev); 114f52228b8SJoe Beteta static void skd_soft_reset(struct skd_device *skdev); 115f52228b8SJoe Beteta static void skd_refresh_device_data(struct skd_device *skdev); 116f52228b8SJoe Beteta static void skd_update_props(skd_device_t *, dev_info_t *); 117f52228b8SJoe Beteta static void skd_end_request_abnormal(struct skd_device *, skd_buf_private_t *, 118f52228b8SJoe Beteta int, int); 119f52228b8SJoe Beteta static char *skd_pci_info(struct skd_device *skdev, char *str, size_t len); 120f52228b8SJoe Beteta 121f52228b8SJoe Beteta static skd_buf_private_t *skd_get_queued_pbuf(skd_device_t *); 122f52228b8SJoe Beteta 123f52228b8SJoe Beteta static void skd_bd_driveinfo(void *arg, bd_drive_t *drive); 124f52228b8SJoe Beteta static int skd_bd_mediainfo(void *arg, bd_media_t *media); 125f52228b8SJoe Beteta static int skd_bd_read(void *arg, bd_xfer_t *xfer); 126f52228b8SJoe Beteta static int skd_bd_write(void *arg, bd_xfer_t *xfer); 127f52228b8SJoe Beteta static int skd_devid_init(void *arg, dev_info_t *, ddi_devid_t *); 128f52228b8SJoe Beteta 129f52228b8SJoe Beteta 130f52228b8SJoe Beteta static bd_ops_t skd_bd_ops = { 131f52228b8SJoe Beteta BD_OPS_VERSION_0, 132f52228b8SJoe Beteta skd_bd_driveinfo, 133f52228b8SJoe Beteta skd_bd_mediainfo, 134f52228b8SJoe Beteta skd_devid_init, 135f52228b8SJoe Beteta NULL, /* sync_cache */ 136f52228b8SJoe Beteta skd_bd_read, 137f52228b8SJoe Beteta skd_bd_write, 138f52228b8SJoe Beteta }; 139f52228b8SJoe Beteta 140f52228b8SJoe Beteta static ddi_device_acc_attr_t dev_acc_attr = { 141f52228b8SJoe Beteta DDI_DEVICE_ATTR_V0, 142f52228b8SJoe Beteta DDI_STRUCTURE_LE_ACC, 143f52228b8SJoe Beteta DDI_STRICTORDER_ACC 144f52228b8SJoe Beteta }; 145f52228b8SJoe Beteta 146f52228b8SJoe Beteta /* 147f52228b8SJoe Beteta * Solaris module loading/unloading structures 148f52228b8SJoe Beteta */ 149f52228b8SJoe Beteta struct dev_ops skd_dev_ops = { 150f52228b8SJoe Beteta DEVO_REV, /* devo_rev */ 151f52228b8SJoe Beteta 0, /* refcnt */ 152f52228b8SJoe Beteta ddi_no_info, /* getinfo */ 153f52228b8SJoe Beteta nulldev, /* identify */ 154f52228b8SJoe Beteta nulldev, /* probe */ 155f52228b8SJoe Beteta skd_attach, /* attach */ 156f52228b8SJoe Beteta skd_detach, /* detach */ 157f52228b8SJoe Beteta nodev, /* reset */ 158f52228b8SJoe Beteta NULL, /* char/block ops */ 159f52228b8SJoe Beteta NULL, /* bus operations */ 160f52228b8SJoe Beteta NULL, /* power management */ 161f52228b8SJoe Beteta skd_sys_quiesce_dev /* quiesce */ 162f52228b8SJoe Beteta }; 163f52228b8SJoe Beteta 164f52228b8SJoe Beteta static struct modldrv modldrv = { 165f52228b8SJoe Beteta &mod_driverops, /* type of module: driver */ 166f52228b8SJoe Beteta "sTec skd v" DRV_VER_COMPL, /* name of module */ 167f52228b8SJoe Beteta &skd_dev_ops /* driver dev_ops */ 168f52228b8SJoe Beteta }; 169f52228b8SJoe Beteta 170f52228b8SJoe Beteta static struct modlinkage modlinkage = { 171f52228b8SJoe Beteta MODREV_1, 172f52228b8SJoe Beteta &modldrv, 173f52228b8SJoe Beteta NULL 174f52228b8SJoe Beteta }; 175f52228b8SJoe Beteta 176f52228b8SJoe Beteta /* 177f52228b8SJoe Beteta * sTec-required wrapper for debug printing. 178f52228b8SJoe Beteta */ 179f52228b8SJoe Beteta /*PRINTFLIKE2*/ 180f52228b8SJoe Beteta static inline void 181f52228b8SJoe Beteta Dcmn_err(int lvl, const char *fmt, ...) 182f52228b8SJoe Beteta { 183f52228b8SJoe Beteta va_list ap; 184f52228b8SJoe Beteta 185f52228b8SJoe Beteta if (skd_dbg_level == 0) 186f52228b8SJoe Beteta return; 187f52228b8SJoe Beteta 188f52228b8SJoe Beteta va_start(ap, fmt); 189f52228b8SJoe Beteta vcmn_err(lvl, fmt, ap); 190f52228b8SJoe Beteta va_end(ap); 191f52228b8SJoe Beteta } 192f52228b8SJoe Beteta 193f52228b8SJoe Beteta /* 194f52228b8SJoe Beteta * Solaris module loading/unloading routines 195f52228b8SJoe Beteta */ 196f52228b8SJoe Beteta 197f52228b8SJoe Beteta /* 198f52228b8SJoe Beteta * 199f52228b8SJoe Beteta * Name: _init, performs initial installation 200f52228b8SJoe Beteta * 201f52228b8SJoe Beteta * Inputs: None. 202f52228b8SJoe Beteta * 203f52228b8SJoe Beteta * Returns: Returns the value returned by the ddi_softstate_init function 204f52228b8SJoe Beteta * on a failure to create the device state structure or the result 205f52228b8SJoe Beteta * of the module install routines. 206f52228b8SJoe Beteta * 207f52228b8SJoe Beteta */ 208f52228b8SJoe Beteta int 209f52228b8SJoe Beteta _init(void) 210f52228b8SJoe Beteta { 211f52228b8SJoe Beteta int rval = 0; 212f52228b8SJoe Beteta int tgts = 0; 213f52228b8SJoe Beteta 214f52228b8SJoe Beteta tgts |= 0x02; 215f52228b8SJoe Beteta tgts |= 0x08; /* In #ifdef NEXENTA block from original sTec drop. */ 216f52228b8SJoe Beteta 217f52228b8SJoe Beteta /* 218f52228b8SJoe Beteta * drv_usectohz() is a function, so can't initialize it at 219f52228b8SJoe Beteta * instantiation. 220f52228b8SJoe Beteta */ 221f52228b8SJoe Beteta skd_timer_ticks = drv_usectohz(1000000); 222f52228b8SJoe Beteta 223f52228b8SJoe Beteta Dcmn_err(CE_NOTE, 224f52228b8SJoe Beteta "<# Installing skd Driver dbg-lvl=%d %s %x>", 225f52228b8SJoe Beteta skd_dbg_level, DRV_BUILD_ID, tgts); 226f52228b8SJoe Beteta 227f52228b8SJoe Beteta rval = ddi_soft_state_init(&skd_state, sizeof (skd_device_t), 0); 228f52228b8SJoe Beteta if (rval != DDI_SUCCESS) 229f52228b8SJoe Beteta return (rval); 230f52228b8SJoe Beteta 231f52228b8SJoe Beteta bd_mod_init(&skd_dev_ops); 232f52228b8SJoe Beteta 233f52228b8SJoe Beteta rval = mod_install(&modlinkage); 234f52228b8SJoe Beteta if (rval != DDI_SUCCESS) { 235f52228b8SJoe Beteta ddi_soft_state_fini(&skd_state); 236f52228b8SJoe Beteta bd_mod_fini(&skd_dev_ops); 237f52228b8SJoe Beteta } 238f52228b8SJoe Beteta 239f52228b8SJoe Beteta return (rval); 240f52228b8SJoe Beteta } 241f52228b8SJoe Beteta 242f52228b8SJoe Beteta /* 243f52228b8SJoe Beteta * 244f52228b8SJoe Beteta * Name: _info, returns information about loadable module. 245f52228b8SJoe Beteta * 246f52228b8SJoe Beteta * Inputs: modinfo, pointer to module information structure. 247f52228b8SJoe Beteta * 248f52228b8SJoe Beteta * Returns: Value returned by mod_info(). 249f52228b8SJoe Beteta * 250f52228b8SJoe Beteta */ 251f52228b8SJoe Beteta int 252f52228b8SJoe Beteta _info(struct modinfo *modinfop) 253f52228b8SJoe Beteta { 254f52228b8SJoe Beteta return (mod_info(&modlinkage, modinfop)); 255f52228b8SJoe Beteta } 256f52228b8SJoe Beteta 257f52228b8SJoe Beteta /* 258f52228b8SJoe Beteta * _fini Prepares a module for unloading. It is called when the system 259f52228b8SJoe Beteta * wants to unload a module. If the module determines that it can 260f52228b8SJoe Beteta * be unloaded, then _fini() returns the value returned by 261f52228b8SJoe Beteta * mod_remove(). Upon successful return from _fini() no other 262f52228b8SJoe Beteta * routine in the module will be called before _init() is called. 263f52228b8SJoe Beteta * 264f52228b8SJoe Beteta * Inputs: None. 265f52228b8SJoe Beteta * 266f52228b8SJoe Beteta * Returns: DDI_SUCCESS or DDI_FAILURE. 267f52228b8SJoe Beteta * 268f52228b8SJoe Beteta */ 269f52228b8SJoe Beteta int 270f52228b8SJoe Beteta _fini(void) 271f52228b8SJoe Beteta { 272f52228b8SJoe Beteta int rval; 273f52228b8SJoe Beteta 274f52228b8SJoe Beteta rval = mod_remove(&modlinkage); 275f52228b8SJoe Beteta if (rval == DDI_SUCCESS) { 276f52228b8SJoe Beteta ddi_soft_state_fini(&skd_state); 277f52228b8SJoe Beteta bd_mod_fini(&skd_dev_ops); 278f52228b8SJoe Beteta } 279f52228b8SJoe Beteta 280f52228b8SJoe Beteta return (rval); 281f52228b8SJoe Beteta } 282f52228b8SJoe Beteta 283f52228b8SJoe Beteta /* 284f52228b8SJoe Beteta * Solaris Register read/write routines 285f52228b8SJoe Beteta */ 286f52228b8SJoe Beteta 287f52228b8SJoe Beteta /* 288f52228b8SJoe Beteta * 289f52228b8SJoe Beteta * Name: skd_reg_write64, writes a 64-bit value to specified address 290f52228b8SJoe Beteta * 291f52228b8SJoe Beteta * Inputs: skdev - device state structure. 292f52228b8SJoe Beteta * val - 64-bit value to be written. 293f52228b8SJoe Beteta * offset - offset from PCI base address. 294f52228b8SJoe Beteta * 295f52228b8SJoe Beteta * Returns: Nothing. 296f52228b8SJoe Beteta * 297f52228b8SJoe Beteta */ 298f52228b8SJoe Beteta /* 299f52228b8SJoe Beteta * Local vars are to keep lint silent. Any compiler worth its weight will 300f52228b8SJoe Beteta * optimize it all right out... 301f52228b8SJoe Beteta */ 302f52228b8SJoe Beteta static inline void 303f52228b8SJoe Beteta skd_reg_write64(struct skd_device *skdev, uint64_t val, uint32_t offset) 304f52228b8SJoe Beteta { 305f52228b8SJoe Beteta uint64_t *addr; 306f52228b8SJoe Beteta 307f52228b8SJoe Beteta ASSERT((offset & 0x7) == 0); 308f52228b8SJoe Beteta /* LINTED */ 309f52228b8SJoe Beteta addr = (uint64_t *)(skdev->dev_iobase + offset); 310f52228b8SJoe Beteta ddi_put64(skdev->dev_handle, addr, val); 311f52228b8SJoe Beteta } 312f52228b8SJoe Beteta 313f52228b8SJoe Beteta /* 314f52228b8SJoe Beteta * 315f52228b8SJoe Beteta * Name: skd_reg_read32, reads a 32-bit value to specified address 316f52228b8SJoe Beteta * 317f52228b8SJoe Beteta * Inputs: skdev - device state structure. 318f52228b8SJoe Beteta * offset - offset from PCI base address. 319f52228b8SJoe Beteta * 320f52228b8SJoe Beteta * Returns: val, 32-bit value read from specified PCI address. 321f52228b8SJoe Beteta * 322f52228b8SJoe Beteta */ 323f52228b8SJoe Beteta static inline uint32_t 324f52228b8SJoe Beteta skd_reg_read32(struct skd_device *skdev, uint32_t offset) 325f52228b8SJoe Beteta { 326f52228b8SJoe Beteta uint32_t *addr; 327f52228b8SJoe Beteta 328f52228b8SJoe Beteta ASSERT((offset & 0x3) == 0); 329f52228b8SJoe Beteta /* LINTED */ 330f52228b8SJoe Beteta addr = (uint32_t *)(skdev->dev_iobase + offset); 331f52228b8SJoe Beteta return (ddi_get32(skdev->dev_handle, addr)); 332f52228b8SJoe Beteta } 333f52228b8SJoe Beteta 334f52228b8SJoe Beteta /* 335f52228b8SJoe Beteta * 336f52228b8SJoe Beteta * Name: skd_reg_write32, writes a 32-bit value to specified address 337f52228b8SJoe Beteta * 338f52228b8SJoe Beteta * Inputs: skdev - device state structure. 339f52228b8SJoe Beteta * val - value to be written. 340f52228b8SJoe Beteta * offset - offset from PCI base address. 341f52228b8SJoe Beteta * 342f52228b8SJoe Beteta * Returns: Nothing. 343f52228b8SJoe Beteta * 344f52228b8SJoe Beteta */ 345f52228b8SJoe Beteta static inline void 346f52228b8SJoe Beteta skd_reg_write32(struct skd_device *skdev, uint32_t val, uint32_t offset) 347f52228b8SJoe Beteta { 348f52228b8SJoe Beteta uint32_t *addr; 349f52228b8SJoe Beteta 350f52228b8SJoe Beteta ASSERT((offset & 0x3) == 0); 351f52228b8SJoe Beteta /* LINTED */ 352f52228b8SJoe Beteta addr = (uint32_t *)(skdev->dev_iobase + offset); 353f52228b8SJoe Beteta ddi_put32(skdev->dev_handle, addr, val); 354f52228b8SJoe Beteta } 355f52228b8SJoe Beteta 356f52228b8SJoe Beteta 357f52228b8SJoe Beteta /* 358f52228b8SJoe Beteta * Solaris skd routines 359f52228b8SJoe Beteta */ 360f52228b8SJoe Beteta 361f52228b8SJoe Beteta /* 362f52228b8SJoe Beteta * 363f52228b8SJoe Beteta * Name: skd_name, generates the name of the driver. 364f52228b8SJoe Beteta * 365f52228b8SJoe Beteta * Inputs: skdev - device state structure 366f52228b8SJoe Beteta * 367f52228b8SJoe Beteta * Returns: char pointer to generated driver name. 368f52228b8SJoe Beteta * 369f52228b8SJoe Beteta */ 370f52228b8SJoe Beteta static const char * 371f52228b8SJoe Beteta skd_name(struct skd_device *skdev) 372f52228b8SJoe Beteta { 373f52228b8SJoe Beteta (void) snprintf(skdev->id_str, sizeof (skdev->id_str), "%s:", DRV_NAME); 374f52228b8SJoe Beteta 375f52228b8SJoe Beteta return (skdev->id_str); 376f52228b8SJoe Beteta } 377f52228b8SJoe Beteta 378f52228b8SJoe Beteta /* 379f52228b8SJoe Beteta * 380f52228b8SJoe Beteta * Name: skd_pci_find_capability, searches the PCI capability 381f52228b8SJoe Beteta * list for the specified capability. 382f52228b8SJoe Beteta * 383f52228b8SJoe Beteta * Inputs: skdev - device state structure. 384f52228b8SJoe Beteta * cap - capability sought. 385f52228b8SJoe Beteta * 386f52228b8SJoe Beteta * Returns: Returns position where capability was found. 387f52228b8SJoe Beteta * If not found, returns zero. 388f52228b8SJoe Beteta * 389f52228b8SJoe Beteta */ 390f52228b8SJoe Beteta static int 391f52228b8SJoe Beteta skd_pci_find_capability(struct skd_device *skdev, int cap) 392f52228b8SJoe Beteta { 393f52228b8SJoe Beteta uint16_t status; 394f52228b8SJoe Beteta uint8_t pos, id, hdr; 395f52228b8SJoe Beteta int ttl = 48; 396f52228b8SJoe Beteta 397f52228b8SJoe Beteta status = pci_config_get16(skdev->pci_handle, PCI_CONF_STAT); 398f52228b8SJoe Beteta 399f52228b8SJoe Beteta if (!(status & PCI_STAT_CAP)) 400f52228b8SJoe Beteta return (0); 401f52228b8SJoe Beteta 402f52228b8SJoe Beteta hdr = pci_config_get8(skdev->pci_handle, PCI_CONF_HEADER); 403f52228b8SJoe Beteta 404f52228b8SJoe Beteta if ((hdr & PCI_HEADER_TYPE_M) != 0) 405f52228b8SJoe Beteta return (0); 406f52228b8SJoe Beteta 407f52228b8SJoe Beteta pos = pci_config_get8(skdev->pci_handle, PCI_CONF_CAP_PTR); 408f52228b8SJoe Beteta 409f52228b8SJoe Beteta while (ttl-- && pos >= 0x40) { 410f52228b8SJoe Beteta pos &= ~3; 411f52228b8SJoe Beteta id = pci_config_get8(skdev->pci_handle, pos+PCI_CAP_ID); 412f52228b8SJoe Beteta if (id == 0xff) 413f52228b8SJoe Beteta break; 414f52228b8SJoe Beteta if (id == cap) 415f52228b8SJoe Beteta return (pos); 416f52228b8SJoe Beteta pos = pci_config_get8(skdev->pci_handle, pos+PCI_CAP_NEXT_PTR); 417f52228b8SJoe Beteta } 418f52228b8SJoe Beteta 419f52228b8SJoe Beteta return (0); 420f52228b8SJoe Beteta } 421f52228b8SJoe Beteta 422f52228b8SJoe Beteta /* 423f52228b8SJoe Beteta * 424f52228b8SJoe Beteta * Name: skd_io_done, called to conclude an I/O operation. 425f52228b8SJoe Beteta * 426f52228b8SJoe Beteta * Inputs: skdev - device state structure. 427f52228b8SJoe Beteta * pbuf - I/O request 428f52228b8SJoe Beteta * error - contain error value. 429f52228b8SJoe Beteta * mode - debug only. 430f52228b8SJoe Beteta * 431f52228b8SJoe Beteta * Returns: Nothing. 432f52228b8SJoe Beteta * 433f52228b8SJoe Beteta */ 434f52228b8SJoe Beteta static void 435f52228b8SJoe Beteta skd_io_done(skd_device_t *skdev, skd_buf_private_t *pbuf, 436f52228b8SJoe Beteta int error, int mode) 437f52228b8SJoe Beteta { 438f52228b8SJoe Beteta bd_xfer_t *xfer; 439f52228b8SJoe Beteta 440f52228b8SJoe Beteta ASSERT(pbuf != NULL); 441f52228b8SJoe Beteta 442f52228b8SJoe Beteta xfer = pbuf->x_xfer; 443f52228b8SJoe Beteta 444f52228b8SJoe Beteta switch (mode) { 445f52228b8SJoe Beteta case SKD_IODONE_WIOC: 446f52228b8SJoe Beteta skdev->iodone_wioc++; 447f52228b8SJoe Beteta break; 448f52228b8SJoe Beteta case SKD_IODONE_WNIOC: 449f52228b8SJoe Beteta skdev->iodone_wnioc++; 450f52228b8SJoe Beteta break; 451f52228b8SJoe Beteta case SKD_IODONE_WDEBUG: 452f52228b8SJoe Beteta skdev->iodone_wdebug++; 453f52228b8SJoe Beteta break; 454f52228b8SJoe Beteta default: 455f52228b8SJoe Beteta skdev->iodone_unknown++; 456f52228b8SJoe Beteta } 457f52228b8SJoe Beteta 458f52228b8SJoe Beteta if (error) { 459f52228b8SJoe Beteta skdev->ios_errors++; 460f52228b8SJoe Beteta cmn_err(CE_WARN, 461f52228b8SJoe Beteta "!%s:skd_io_done:ERR=%d %lld-%ld %s", skdev->name, 462f52228b8SJoe Beteta error, xfer->x_blkno, xfer->x_nblks, 463f52228b8SJoe Beteta (pbuf->dir & B_READ) ? "Read" : "Write"); 464f52228b8SJoe Beteta } 465f52228b8SJoe Beteta 466f52228b8SJoe Beteta kmem_free(pbuf, sizeof (skd_buf_private_t)); 467f52228b8SJoe Beteta 468f52228b8SJoe Beteta bd_xfer_done(xfer, error); 469f52228b8SJoe Beteta } 470f52228b8SJoe Beteta 471f52228b8SJoe Beteta /* 472f52228b8SJoe Beteta * QUIESCE DEVICE 473f52228b8SJoe Beteta */ 474f52228b8SJoe Beteta 475f52228b8SJoe Beteta /* 476f52228b8SJoe Beteta * 477f52228b8SJoe Beteta * Name: skd_sys_quiesce_dev, quiets the device 478f52228b8SJoe Beteta * 479f52228b8SJoe Beteta * Inputs: dip - dev info strucuture 480f52228b8SJoe Beteta * 481f52228b8SJoe Beteta * Returns: Zero. 482f52228b8SJoe Beteta * 483f52228b8SJoe Beteta */ 484f52228b8SJoe Beteta static int 485f52228b8SJoe Beteta skd_sys_quiesce_dev(dev_info_t *dip) 486f52228b8SJoe Beteta { 487f52228b8SJoe Beteta skd_device_t *skdev; 488f52228b8SJoe Beteta 489f52228b8SJoe Beteta skdev = ddi_get_soft_state(skd_state, ddi_get_instance(dip)); 490f52228b8SJoe Beteta 491f52228b8SJoe Beteta /* make sure Dcmn_err() doesn't actually print anything */ 492f52228b8SJoe Beteta skd_dbg_level = 0; 493f52228b8SJoe Beteta 494f52228b8SJoe Beteta skd_disable_interrupts(skdev); 495f52228b8SJoe Beteta skd_soft_reset(skdev); 496f52228b8SJoe Beteta 497f52228b8SJoe Beteta return (0); 498f52228b8SJoe Beteta } 499f52228b8SJoe Beteta 500f52228b8SJoe Beteta /* 501f52228b8SJoe Beteta * 502f52228b8SJoe Beteta * Name: skd_quiesce_dev, quiets the device, but doesn't really do much. 503f52228b8SJoe Beteta * 504f52228b8SJoe Beteta * Inputs: skdev - Device state. 505f52228b8SJoe Beteta * 506f52228b8SJoe Beteta * Returns: -EINVAL if device is not in proper state otherwise 507f52228b8SJoe Beteta * returns zero. 508f52228b8SJoe Beteta * 509f52228b8SJoe Beteta */ 510f52228b8SJoe Beteta static int 511f52228b8SJoe Beteta skd_quiesce_dev(skd_device_t *skdev) 512f52228b8SJoe Beteta { 513f52228b8SJoe Beteta int rc = 0; 514f52228b8SJoe Beteta 515f52228b8SJoe Beteta if (skd_dbg_level) 516f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "skd_quiece_dev:"); 517f52228b8SJoe Beteta 518f52228b8SJoe Beteta switch (skdev->state) { 519f52228b8SJoe Beteta case SKD_DRVR_STATE_BUSY: 520f52228b8SJoe Beteta case SKD_DRVR_STATE_BUSY_IMMINENT: 521f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "%s: stopping queue", skdev->name); 522f52228b8SJoe Beteta break; 523f52228b8SJoe Beteta case SKD_DRVR_STATE_ONLINE: 524f52228b8SJoe Beteta case SKD_DRVR_STATE_STOPPING: 525f52228b8SJoe Beteta case SKD_DRVR_STATE_SYNCING: 526f52228b8SJoe Beteta case SKD_DRVR_STATE_PAUSING: 527f52228b8SJoe Beteta case SKD_DRVR_STATE_PAUSED: 528f52228b8SJoe Beteta case SKD_DRVR_STATE_STARTING: 529f52228b8SJoe Beteta case SKD_DRVR_STATE_RESTARTING: 530f52228b8SJoe Beteta case SKD_DRVR_STATE_RESUMING: 531f52228b8SJoe Beteta default: 532f52228b8SJoe Beteta rc = -EINVAL; 533f52228b8SJoe Beteta cmn_err(CE_NOTE, "state [%d] not implemented", skdev->state); 534f52228b8SJoe Beteta } 535f52228b8SJoe Beteta 536f52228b8SJoe Beteta return (rc); 537f52228b8SJoe Beteta } 538f52228b8SJoe Beteta 539f52228b8SJoe Beteta /* 540f52228b8SJoe Beteta * UNQUIESCE DEVICE: 541f52228b8SJoe Beteta * Note: Assumes lock is held to protect device state. 542f52228b8SJoe Beteta */ 543f52228b8SJoe Beteta /* 544f52228b8SJoe Beteta * 545f52228b8SJoe Beteta * Name: skd_unquiesce_dev, awkens the device 546f52228b8SJoe Beteta * 547f52228b8SJoe Beteta * Inputs: skdev - Device state. 548f52228b8SJoe Beteta * 549f52228b8SJoe Beteta * Returns: -EINVAL if device is not in proper state otherwise 550f52228b8SJoe Beteta * returns zero. 551f52228b8SJoe Beteta * 552f52228b8SJoe Beteta */ 553f52228b8SJoe Beteta static int 554f52228b8SJoe Beteta skd_unquiesce_dev(struct skd_device *skdev) 555f52228b8SJoe Beteta { 556f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "skd_unquiece_dev:"); 557f52228b8SJoe Beteta 558f52228b8SJoe Beteta skd_log_skdev(skdev, "unquiesce"); 559f52228b8SJoe Beteta if (skdev->state == SKD_DRVR_STATE_ONLINE) { 560f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "**** device already ONLINE"); 561f52228b8SJoe Beteta 562f52228b8SJoe Beteta return (0); 563f52228b8SJoe Beteta } 564f52228b8SJoe Beteta if (skdev->drive_state != FIT_SR_DRIVE_ONLINE) { 565f52228b8SJoe Beteta /* 566f52228b8SJoe Beteta * If there has been an state change to other than 567f52228b8SJoe Beteta * ONLINE, we will rely on controller state change 568f52228b8SJoe Beteta * to come back online and restart the queue. 569f52228b8SJoe Beteta * The BUSY state means that driver is ready to 570f52228b8SJoe Beteta * continue normal processing but waiting for controller 571f52228b8SJoe Beteta * to become available. 572f52228b8SJoe Beteta */ 573f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_BUSY; 574f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "drive BUSY state\n"); 575f52228b8SJoe Beteta 576f52228b8SJoe Beteta return (0); 577f52228b8SJoe Beteta } 578f52228b8SJoe Beteta /* 579f52228b8SJoe Beteta * Drive just come online, driver is either in startup, 580f52228b8SJoe Beteta * paused performing a task, or bust waiting for hardware. 581f52228b8SJoe Beteta */ 582f52228b8SJoe Beteta switch (skdev->state) { 583f52228b8SJoe Beteta case SKD_DRVR_STATE_PAUSED: 584f52228b8SJoe Beteta case SKD_DRVR_STATE_BUSY: 585f52228b8SJoe Beteta case SKD_DRVR_STATE_BUSY_IMMINENT: 586f52228b8SJoe Beteta case SKD_DRVR_STATE_BUSY_ERASE: 587f52228b8SJoe Beteta case SKD_DRVR_STATE_STARTING: 588f52228b8SJoe Beteta case SKD_DRVR_STATE_RESTARTING: 589f52228b8SJoe Beteta case SKD_DRVR_STATE_FAULT: 590f52228b8SJoe Beteta case SKD_DRVR_STATE_IDLE: 591f52228b8SJoe Beteta case SKD_DRVR_STATE_LOAD: 592f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_ONLINE; 593f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "%s: sTec s1120 ONLINE", skdev->name); 594f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "%s: Starting request queue", skdev->name); 595f52228b8SJoe Beteta Dcmn_err(CE_NOTE, 596f52228b8SJoe Beteta "%s: queue depth limit=%d hard=%d soft=%d lowat=%d", 597f52228b8SJoe Beteta skdev->name, 598f52228b8SJoe Beteta skdev->queue_depth_limit, 599f52228b8SJoe Beteta skdev->hard_queue_depth_limit, 600f52228b8SJoe Beteta skdev->soft_queue_depth_limit, 601f52228b8SJoe Beteta skdev->queue_depth_lowat); 602f52228b8SJoe Beteta 603f52228b8SJoe Beteta skdev->gendisk_on = 1; 604f52228b8SJoe Beteta cv_signal(&skdev->cv_waitq); 605f52228b8SJoe Beteta break; 606f52228b8SJoe Beteta case SKD_DRVR_STATE_DISAPPEARED: 607f52228b8SJoe Beteta default: 608f52228b8SJoe Beteta cmn_err(CE_NOTE, "**** driver state %d, not implemented \n", 609f52228b8SJoe Beteta skdev->state); 610f52228b8SJoe Beteta return (-EBUSY); 611f52228b8SJoe Beteta } 612f52228b8SJoe Beteta 613f52228b8SJoe Beteta return (0); 614f52228b8SJoe Beteta } 615f52228b8SJoe Beteta 616f52228b8SJoe Beteta /* 617f52228b8SJoe Beteta * READ/WRITE REQUESTS 618f52228b8SJoe Beteta */ 619f52228b8SJoe Beteta 620f52228b8SJoe Beteta /* 621f52228b8SJoe Beteta * 622f52228b8SJoe Beteta * Name: skd_blkdev_preop_sg_list, builds the S/G list from info 623f52228b8SJoe Beteta * passed in by the blkdev driver. 624f52228b8SJoe Beteta * 625f52228b8SJoe Beteta * Inputs: skdev - device state structure. 626f52228b8SJoe Beteta * skreq - request structure. 627f52228b8SJoe Beteta * sg_byte_count - data transfer byte count. 628f52228b8SJoe Beteta * 629f52228b8SJoe Beteta * Returns: Nothing. 630f52228b8SJoe Beteta * 631f52228b8SJoe Beteta */ 632f52228b8SJoe Beteta /*ARGSUSED*/ 633f52228b8SJoe Beteta static void 634f52228b8SJoe Beteta skd_blkdev_preop_sg_list(struct skd_device *skdev, 635f52228b8SJoe Beteta struct skd_request_context *skreq, uint32_t *sg_byte_count) 636f52228b8SJoe Beteta { 637f52228b8SJoe Beteta bd_xfer_t *xfer; 638f52228b8SJoe Beteta skd_buf_private_t *pbuf; 639f52228b8SJoe Beteta int i, bcount = 0; 640f52228b8SJoe Beteta uint_t n_sg; 641f52228b8SJoe Beteta 642f52228b8SJoe Beteta *sg_byte_count = 0; 643f52228b8SJoe Beteta 644f52228b8SJoe Beteta ASSERT(skreq->sg_data_dir == SKD_DATA_DIR_HOST_TO_CARD || 645f52228b8SJoe Beteta skreq->sg_data_dir == SKD_DATA_DIR_CARD_TO_HOST); 646f52228b8SJoe Beteta 647f52228b8SJoe Beteta pbuf = skreq->pbuf; 648f52228b8SJoe Beteta ASSERT(pbuf != NULL); 649f52228b8SJoe Beteta 650f52228b8SJoe Beteta xfer = pbuf->x_xfer; 651f52228b8SJoe Beteta n_sg = xfer->x_ndmac; 652f52228b8SJoe Beteta 653f52228b8SJoe Beteta ASSERT(n_sg <= skdev->sgs_per_request); 654f52228b8SJoe Beteta 655f52228b8SJoe Beteta skreq->n_sg = n_sg; 656f52228b8SJoe Beteta 657f52228b8SJoe Beteta skreq->io_dma_handle = xfer->x_dmah; 658f52228b8SJoe Beteta 659f52228b8SJoe Beteta skreq->total_sg_bcount = 0; 660f52228b8SJoe Beteta 661f52228b8SJoe Beteta for (i = 0; i < n_sg; i++) { 662f52228b8SJoe Beteta ddi_dma_cookie_t *cookiep = &xfer->x_dmac; 663f52228b8SJoe Beteta struct fit_sg_descriptor *sgd; 664f52228b8SJoe Beteta uint32_t cnt = (uint32_t)cookiep->dmac_size; 665f52228b8SJoe Beteta 666f52228b8SJoe Beteta bcount += cnt; 667f52228b8SJoe Beteta 668f52228b8SJoe Beteta sgd = &skreq->sksg_list[i]; 669f52228b8SJoe Beteta sgd->control = FIT_SGD_CONTROL_NOT_LAST; 670f52228b8SJoe Beteta sgd->byte_count = cnt; 671f52228b8SJoe Beteta sgd->host_side_addr = cookiep->dmac_laddress; 672f52228b8SJoe Beteta sgd->dev_side_addr = 0; /* not used */ 673f52228b8SJoe Beteta *sg_byte_count += cnt; 674f52228b8SJoe Beteta 675f52228b8SJoe Beteta skreq->total_sg_bcount += cnt; 676f52228b8SJoe Beteta 677f52228b8SJoe Beteta if ((i + 1) != n_sg) 678f52228b8SJoe Beteta ddi_dma_nextcookie(skreq->io_dma_handle, &xfer->x_dmac); 679f52228b8SJoe Beteta } 680f52228b8SJoe Beteta 681f52228b8SJoe Beteta skreq->sksg_list[n_sg - 1].next_desc_ptr = 0LL; 682f52228b8SJoe Beteta skreq->sksg_list[n_sg - 1].control = FIT_SGD_CONTROL_LAST; 683f52228b8SJoe Beteta 684f52228b8SJoe Beteta (void) ddi_dma_sync(skreq->sksg_dma_address.dma_handle, 0, 0, 685f52228b8SJoe Beteta DDI_DMA_SYNC_FORDEV); 686f52228b8SJoe Beteta } 687f52228b8SJoe Beteta 688f52228b8SJoe Beteta /* 689f52228b8SJoe Beteta * 690f52228b8SJoe Beteta * Name: skd_blkdev_postop_sg_list, deallocates DMA 691f52228b8SJoe Beteta * 692f52228b8SJoe Beteta * Inputs: skdev - device state structure. 693f52228b8SJoe Beteta * skreq - skreq data structure. 694f52228b8SJoe Beteta * 695f52228b8SJoe Beteta * Returns: Nothing. 696f52228b8SJoe Beteta * 697f52228b8SJoe Beteta */ 698f52228b8SJoe Beteta /* ARGSUSED */ /* Upstream common source with other platforms. */ 699f52228b8SJoe Beteta static void 700f52228b8SJoe Beteta skd_blkdev_postop_sg_list(struct skd_device *skdev, 701f52228b8SJoe Beteta struct skd_request_context *skreq) 702f52228b8SJoe Beteta { 703f52228b8SJoe Beteta /* 704f52228b8SJoe Beteta * restore the next ptr for next IO request so we 705f52228b8SJoe Beteta * don't have to set it every time. 706f52228b8SJoe Beteta */ 707f52228b8SJoe Beteta skreq->sksg_list[skreq->n_sg - 1].next_desc_ptr = 708f52228b8SJoe Beteta skreq->sksg_dma_address.cookies->dmac_laddress + 709f52228b8SJoe Beteta ((skreq->n_sg) * sizeof (struct fit_sg_descriptor)); 710f52228b8SJoe Beteta } 711f52228b8SJoe Beteta 712f52228b8SJoe Beteta /* 713f52228b8SJoe Beteta * 714f52228b8SJoe Beteta * Name: skd_start, initiates an I/O. 715f52228b8SJoe Beteta * 716f52228b8SJoe Beteta * Inputs: skdev - device state structure. 717f52228b8SJoe Beteta * 718f52228b8SJoe Beteta * Returns: EAGAIN if devicfe is not ONLINE. 719f52228b8SJoe Beteta * On error, if the caller is the blkdev driver, return 720f52228b8SJoe Beteta * the error value. Otherwise, return zero. 721f52228b8SJoe Beteta * 722f52228b8SJoe Beteta */ 723f52228b8SJoe Beteta /* Upstream common source with other platforms. */ 724f52228b8SJoe Beteta static void 725f52228b8SJoe Beteta skd_start(skd_device_t *skdev) 726f52228b8SJoe Beteta { 727f52228b8SJoe Beteta struct skd_fitmsg_context *skmsg = NULL; 728f52228b8SJoe Beteta struct fit_msg_hdr *fmh = NULL; 729f52228b8SJoe Beteta struct skd_request_context *skreq = NULL; 730f52228b8SJoe Beteta struct waitqueue *waitq = &skdev->waitqueue; 731f52228b8SJoe Beteta struct skd_scsi_request *scsi_req; 732f52228b8SJoe Beteta skd_buf_private_t *pbuf = NULL; 733f52228b8SJoe Beteta int bcount; 734f52228b8SJoe Beteta 735f52228b8SJoe Beteta uint32_t lba; 736f52228b8SJoe Beteta uint32_t count; 737f52228b8SJoe Beteta uint32_t timo_slot; 738f52228b8SJoe Beteta void *cmd_ptr; 739f52228b8SJoe Beteta uint32_t sg_byte_count = 0; 740f52228b8SJoe Beteta 741f52228b8SJoe Beteta /* 742f52228b8SJoe Beteta * Stop conditions: 743f52228b8SJoe Beteta * - There are no more native requests 744f52228b8SJoe Beteta * - There are already the maximum number of requests is progress 745f52228b8SJoe Beteta * - There are no more skd_request_context entries 746f52228b8SJoe Beteta * - There are no more FIT msg buffers 747f52228b8SJoe Beteta */ 748f52228b8SJoe Beteta for (;;) { 749f52228b8SJoe Beteta /* Are too many requests already in progress? */ 750f52228b8SJoe Beteta if (skdev->queue_depth_busy >= skdev->queue_depth_limit) { 751f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "qdepth %d, limit %d\n", 752f52228b8SJoe Beteta skdev->queue_depth_busy, 753f52228b8SJoe Beteta skdev->queue_depth_limit); 754f52228b8SJoe Beteta break; 755f52228b8SJoe Beteta } 756f52228b8SJoe Beteta 757f52228b8SJoe Beteta WAITQ_LOCK(skdev); 758f52228b8SJoe Beteta if (SIMPLEQ_EMPTY(waitq)) { 759f52228b8SJoe Beteta WAITQ_UNLOCK(skdev); 760f52228b8SJoe Beteta break; 761f52228b8SJoe Beteta } 762f52228b8SJoe Beteta 763f52228b8SJoe Beteta /* Is a skd_request_context available? */ 764f52228b8SJoe Beteta skreq = skdev->skreq_free_list; 765f52228b8SJoe Beteta if (skreq == NULL) { 766f52228b8SJoe Beteta WAITQ_UNLOCK(skdev); 767f52228b8SJoe Beteta break; 768f52228b8SJoe Beteta } 769f52228b8SJoe Beteta 770f52228b8SJoe Beteta ASSERT(skreq->state == SKD_REQ_STATE_IDLE); 771f52228b8SJoe Beteta ASSERT((skreq->id & SKD_ID_INCR) == 0); 772f52228b8SJoe Beteta 773f52228b8SJoe Beteta skdev->skreq_free_list = skreq->next; 774f52228b8SJoe Beteta 775f52228b8SJoe Beteta skreq->state = SKD_REQ_STATE_BUSY; 776f52228b8SJoe Beteta skreq->id += SKD_ID_INCR; 777f52228b8SJoe Beteta 778f52228b8SJoe Beteta /* Start a new FIT msg if there is none in progress. */ 779f52228b8SJoe Beteta if (skmsg == NULL) { 780f52228b8SJoe Beteta /* Are there any FIT msg buffers available? */ 781f52228b8SJoe Beteta skmsg = skdev->skmsg_free_list; 782f52228b8SJoe Beteta if (skmsg == NULL) { 783f52228b8SJoe Beteta WAITQ_UNLOCK(skdev); 784f52228b8SJoe Beteta break; 785f52228b8SJoe Beteta } 786f52228b8SJoe Beteta 787f52228b8SJoe Beteta ASSERT(skmsg->state == SKD_MSG_STATE_IDLE); 788f52228b8SJoe Beteta ASSERT((skmsg->id & SKD_ID_INCR) == 0); 789f52228b8SJoe Beteta 790f52228b8SJoe Beteta skdev->skmsg_free_list = skmsg->next; 791f52228b8SJoe Beteta 792f52228b8SJoe Beteta skmsg->state = SKD_MSG_STATE_BUSY; 793f52228b8SJoe Beteta skmsg->id += SKD_ID_INCR; 794f52228b8SJoe Beteta 795f52228b8SJoe Beteta /* Initialize the FIT msg header */ 796f52228b8SJoe Beteta fmh = (struct fit_msg_hdr *)skmsg->msg_buf64; 797f52228b8SJoe Beteta bzero(fmh, sizeof (*fmh)); /* Too expensive */ 798f52228b8SJoe Beteta fmh->protocol_id = FIT_PROTOCOL_ID_SOFIT; 799f52228b8SJoe Beteta skmsg->length = sizeof (struct fit_msg_hdr); 800f52228b8SJoe Beteta } 801f52228b8SJoe Beteta 802f52228b8SJoe Beteta /* 803f52228b8SJoe Beteta * At this point we are committed to either start or reject 804f52228b8SJoe Beteta * the native request. Note that a FIT msg may have just been 805f52228b8SJoe Beteta * started but contains no SoFIT requests yet. 806f52228b8SJoe Beteta * Now - dequeue pbuf. 807f52228b8SJoe Beteta */ 808f52228b8SJoe Beteta pbuf = skd_get_queued_pbuf(skdev); 809f52228b8SJoe Beteta WAITQ_UNLOCK(skdev); 810f52228b8SJoe Beteta 811f52228b8SJoe Beteta skreq->pbuf = pbuf; 812f52228b8SJoe Beteta lba = pbuf->x_xfer->x_blkno; 813f52228b8SJoe Beteta count = pbuf->x_xfer->x_nblks; 814f52228b8SJoe Beteta skreq->did_complete = 0; 815f52228b8SJoe Beteta 816f52228b8SJoe Beteta skreq->fitmsg_id = skmsg->id; 817f52228b8SJoe Beteta 818f52228b8SJoe Beteta Dcmn_err(CE_NOTE, 819f52228b8SJoe Beteta "pbuf=%p lba=%u(0x%x) count=%u(0x%x) dir=%x\n", 820f52228b8SJoe Beteta (void *)pbuf, lba, lba, count, count, pbuf->dir); 821f52228b8SJoe Beteta 822f52228b8SJoe Beteta /* 823f52228b8SJoe Beteta * Transcode the request. 824f52228b8SJoe Beteta */ 825f52228b8SJoe Beteta cmd_ptr = &skmsg->msg_buf[skmsg->length]; 826f52228b8SJoe Beteta bzero(cmd_ptr, 32); /* This is too expensive */ 827f52228b8SJoe Beteta 828f52228b8SJoe Beteta scsi_req = cmd_ptr; 829f52228b8SJoe Beteta scsi_req->hdr.tag = skreq->id; 830f52228b8SJoe Beteta scsi_req->hdr.sg_list_dma_address = 831f52228b8SJoe Beteta cpu_to_be64(skreq->sksg_dma_address.cookies->dmac_laddress); 832f52228b8SJoe Beteta scsi_req->cdb[1] = 0; 833f52228b8SJoe Beteta scsi_req->cdb[2] = (lba & 0xff000000) >> 24; 834f52228b8SJoe Beteta scsi_req->cdb[3] = (lba & 0xff0000) >> 16; 835f52228b8SJoe Beteta scsi_req->cdb[4] = (lba & 0xff00) >> 8; 836f52228b8SJoe Beteta scsi_req->cdb[5] = (lba & 0xff); 837f52228b8SJoe Beteta scsi_req->cdb[6] = 0; 838f52228b8SJoe Beteta scsi_req->cdb[7] = (count & 0xff00) >> 8; 839f52228b8SJoe Beteta scsi_req->cdb[8] = count & 0xff; 840f52228b8SJoe Beteta scsi_req->cdb[9] = 0; 841f52228b8SJoe Beteta 842f52228b8SJoe Beteta if (pbuf->dir & B_READ) { 843f52228b8SJoe Beteta scsi_req->cdb[0] = 0x28; 844f52228b8SJoe Beteta skreq->sg_data_dir = SKD_DATA_DIR_CARD_TO_HOST; 845f52228b8SJoe Beteta } else { 846f52228b8SJoe Beteta scsi_req->cdb[0] = 0x2a; 847f52228b8SJoe Beteta skreq->sg_data_dir = SKD_DATA_DIR_HOST_TO_CARD; 848f52228b8SJoe Beteta } 849f52228b8SJoe Beteta 850f52228b8SJoe Beteta skd_blkdev_preop_sg_list(skdev, skreq, &sg_byte_count); 851f52228b8SJoe Beteta 852f52228b8SJoe Beteta scsi_req->hdr.sg_list_len_bytes = cpu_to_be32(sg_byte_count); 853f52228b8SJoe Beteta 854f52228b8SJoe Beteta bcount = (sg_byte_count + 511) / 512; 855f52228b8SJoe Beteta scsi_req->cdb[7] = (bcount & 0xff00) >> 8; 856f52228b8SJoe Beteta scsi_req->cdb[8] = bcount & 0xff; 857f52228b8SJoe Beteta 858f52228b8SJoe Beteta Dcmn_err(CE_NOTE, 859f52228b8SJoe Beteta "skd_start: pbuf=%p skreq->id=%x opc=%x ====>>>>>", 860f52228b8SJoe Beteta (void *)pbuf, skreq->id, *scsi_req->cdb); 861f52228b8SJoe Beteta 862f52228b8SJoe Beteta skmsg->length += sizeof (struct skd_scsi_request); 863f52228b8SJoe Beteta fmh->num_protocol_cmds_coalesced++; 864f52228b8SJoe Beteta 865f52228b8SJoe Beteta /* 866f52228b8SJoe Beteta * Update the active request counts. 867f52228b8SJoe Beteta * Capture the timeout timestamp. 868f52228b8SJoe Beteta */ 869f52228b8SJoe Beteta skreq->timeout_stamp = skdev->timeout_stamp; 870f52228b8SJoe Beteta timo_slot = skreq->timeout_stamp & SKD_TIMEOUT_SLOT_MASK; 871f52228b8SJoe Beteta 872f52228b8SJoe Beteta atomic_inc_32(&skdev->timeout_slot[timo_slot]); 873f52228b8SJoe Beteta atomic_inc_32(&skdev->queue_depth_busy); 874f52228b8SJoe Beteta 875f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "req=0x%x busy=%d timo_slot=%d", 876f52228b8SJoe Beteta skreq->id, skdev->queue_depth_busy, timo_slot); 877f52228b8SJoe Beteta /* 878f52228b8SJoe Beteta * If the FIT msg buffer is full send it. 879f52228b8SJoe Beteta */ 880f52228b8SJoe Beteta if (skmsg->length >= SKD_N_FITMSG_BYTES || 881f52228b8SJoe Beteta fmh->num_protocol_cmds_coalesced >= skd_max_req_per_msg) { 882f52228b8SJoe Beteta 883f52228b8SJoe Beteta atomic_inc_64(&skdev->active_cmds); 884f52228b8SJoe Beteta pbuf->skreq = skreq; 885f52228b8SJoe Beteta 886f52228b8SJoe Beteta skdev->fitmsg_sent1++; 887f52228b8SJoe Beteta skd_send_fitmsg(skdev, skmsg); 888f52228b8SJoe Beteta 889f52228b8SJoe Beteta skmsg = NULL; 890f52228b8SJoe Beteta fmh = NULL; 891f52228b8SJoe Beteta } 892f52228b8SJoe Beteta } 893f52228b8SJoe Beteta 894f52228b8SJoe Beteta /* 895f52228b8SJoe Beteta * Is a FIT msg in progress? If it is empty put the buffer back 896f52228b8SJoe Beteta * on the free list. If it is non-empty send what we got. 897f52228b8SJoe Beteta * This minimizes latency when there are fewer requests than 898f52228b8SJoe Beteta * what fits in a FIT msg. 899f52228b8SJoe Beteta */ 900f52228b8SJoe Beteta if (skmsg != NULL) { 901f52228b8SJoe Beteta ASSERT(skmsg->length > sizeof (struct fit_msg_hdr)); 902f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "sending msg=%p, len %d", 903f52228b8SJoe Beteta (void *)skmsg, skmsg->length); 904f52228b8SJoe Beteta 905f52228b8SJoe Beteta skdev->active_cmds++; 906f52228b8SJoe Beteta 907f52228b8SJoe Beteta skdev->fitmsg_sent2++; 908f52228b8SJoe Beteta skd_send_fitmsg(skdev, skmsg); 909f52228b8SJoe Beteta } 910f52228b8SJoe Beteta } 911f52228b8SJoe Beteta 912f52228b8SJoe Beteta /* 913f52228b8SJoe Beteta * 914f52228b8SJoe Beteta * Name: skd_end_request 915f52228b8SJoe Beteta * 916f52228b8SJoe Beteta * Inputs: skdev - device state structure. 917f52228b8SJoe Beteta * skreq - request structure. 918f52228b8SJoe Beteta * error - I/O error value. 919f52228b8SJoe Beteta * 920f52228b8SJoe Beteta * Returns: Nothing. 921f52228b8SJoe Beteta * 922f52228b8SJoe Beteta */ 923f52228b8SJoe Beteta static void 924f52228b8SJoe Beteta skd_end_request(struct skd_device *skdev, 925f52228b8SJoe Beteta struct skd_request_context *skreq, int error) 926f52228b8SJoe Beteta { 927f52228b8SJoe Beteta skdev->ios_completed++; 928f52228b8SJoe Beteta skd_io_done(skdev, skreq->pbuf, error, SKD_IODONE_WIOC); 929f52228b8SJoe Beteta skreq->pbuf = NULL; 930f52228b8SJoe Beteta skreq->did_complete = 1; 931f52228b8SJoe Beteta } 932f52228b8SJoe Beteta 933f52228b8SJoe Beteta /* 934f52228b8SJoe Beteta * 935f52228b8SJoe Beteta * Name: skd_end_request_abnormal 936f52228b8SJoe Beteta * 937f52228b8SJoe Beteta * Inputs: skdev - device state structure. 938f52228b8SJoe Beteta * pbuf - I/O request. 939f52228b8SJoe Beteta * error - I/O error value. 940f52228b8SJoe Beteta * mode - debug 941f52228b8SJoe Beteta * 942f52228b8SJoe Beteta * Returns: Nothing. 943f52228b8SJoe Beteta * 944f52228b8SJoe Beteta */ 945f52228b8SJoe Beteta static void 946f52228b8SJoe Beteta skd_end_request_abnormal(skd_device_t *skdev, skd_buf_private_t *pbuf, 947f52228b8SJoe Beteta int error, int mode) 948f52228b8SJoe Beteta { 949f52228b8SJoe Beteta skd_io_done(skdev, pbuf, error, mode); 950f52228b8SJoe Beteta } 951f52228b8SJoe Beteta 952f52228b8SJoe Beteta /* 953f52228b8SJoe Beteta * 954f52228b8SJoe Beteta * Name: skd_request_fn_not_online, handles the condition 955f52228b8SJoe Beteta * of the device not being online. 956f52228b8SJoe Beteta * 957f52228b8SJoe Beteta * Inputs: skdev - device state structure. 958f52228b8SJoe Beteta * 959f52228b8SJoe Beteta * Returns: nothing (void). 960f52228b8SJoe Beteta * 961f52228b8SJoe Beteta */ 962f52228b8SJoe Beteta static void 963f52228b8SJoe Beteta skd_request_fn_not_online(skd_device_t *skdev) 964f52228b8SJoe Beteta { 965f52228b8SJoe Beteta int error; 966f52228b8SJoe Beteta skd_buf_private_t *pbuf; 967f52228b8SJoe Beteta 968f52228b8SJoe Beteta ASSERT(skdev->state != SKD_DRVR_STATE_ONLINE); 969f52228b8SJoe Beteta 970f52228b8SJoe Beteta skd_log_skdev(skdev, "req_not_online"); 971f52228b8SJoe Beteta 972f52228b8SJoe Beteta switch (skdev->state) { 973f52228b8SJoe Beteta case SKD_DRVR_STATE_PAUSING: 974f52228b8SJoe Beteta case SKD_DRVR_STATE_PAUSED: 975f52228b8SJoe Beteta case SKD_DRVR_STATE_STARTING: 976f52228b8SJoe Beteta case SKD_DRVR_STATE_RESTARTING: 977f52228b8SJoe Beteta case SKD_DRVR_STATE_WAIT_BOOT: 978f52228b8SJoe Beteta /* 979f52228b8SJoe Beteta * In case of starting, we haven't started the queue, 980f52228b8SJoe Beteta * so we can't get here... but requests are 981f52228b8SJoe Beteta * possibly hanging out waiting for us because we 982f52228b8SJoe Beteta * reported the dev/skd/0 already. They'll wait 983f52228b8SJoe Beteta * forever if connect doesn't complete. 984f52228b8SJoe Beteta * What to do??? delay dev/skd/0 ?? 985f52228b8SJoe Beteta */ 986f52228b8SJoe Beteta case SKD_DRVR_STATE_BUSY: 987f52228b8SJoe Beteta case SKD_DRVR_STATE_BUSY_IMMINENT: 988f52228b8SJoe Beteta case SKD_DRVR_STATE_BUSY_ERASE: 989f52228b8SJoe Beteta case SKD_DRVR_STATE_DRAINING_TIMEOUT: 990f52228b8SJoe Beteta return; 991f52228b8SJoe Beteta 992f52228b8SJoe Beteta case SKD_DRVR_STATE_BUSY_SANITIZE: 993f52228b8SJoe Beteta case SKD_DRVR_STATE_STOPPING: 994f52228b8SJoe Beteta case SKD_DRVR_STATE_SYNCING: 995f52228b8SJoe Beteta case SKD_DRVR_STATE_FAULT: 996f52228b8SJoe Beteta case SKD_DRVR_STATE_DISAPPEARED: 997f52228b8SJoe Beteta default: 998f52228b8SJoe Beteta error = -EIO; 999f52228b8SJoe Beteta break; 1000f52228b8SJoe Beteta } 1001f52228b8SJoe Beteta 1002f52228b8SJoe Beteta /* 1003f52228b8SJoe Beteta * If we get here, terminate all pending block requeusts 1004f52228b8SJoe Beteta * with EIO and any scsi pass thru with appropriate sense 1005f52228b8SJoe Beteta */ 1006f52228b8SJoe Beteta ASSERT(WAITQ_LOCK_HELD(skdev)); 1007f52228b8SJoe Beteta if (SIMPLEQ_EMPTY(&skdev->waitqueue)) 1008f52228b8SJoe Beteta return; 1009f52228b8SJoe Beteta 1010f52228b8SJoe Beteta while ((pbuf = skd_get_queued_pbuf(skdev))) 1011f52228b8SJoe Beteta skd_end_request_abnormal(skdev, pbuf, error, SKD_IODONE_WNIOC); 1012f52228b8SJoe Beteta 1013f52228b8SJoe Beteta cv_signal(&skdev->cv_waitq); 1014f52228b8SJoe Beteta } 1015f52228b8SJoe Beteta 1016f52228b8SJoe Beteta /* 1017f52228b8SJoe Beteta * TIMER 1018f52228b8SJoe Beteta */ 1019f52228b8SJoe Beteta 1020f52228b8SJoe Beteta static void skd_timer_tick_not_online(struct skd_device *skdev); 1021f52228b8SJoe Beteta 1022f52228b8SJoe Beteta /* 1023f52228b8SJoe Beteta * 1024f52228b8SJoe Beteta * Name: skd_timer_tick, monitors requests for timeouts. 1025f52228b8SJoe Beteta * 1026f52228b8SJoe Beteta * Inputs: skdev - device state structure. 1027f52228b8SJoe Beteta * 1028f52228b8SJoe Beteta * Returns: Nothing. 1029f52228b8SJoe Beteta * 1030f52228b8SJoe Beteta */ 1031f52228b8SJoe Beteta static void 1032f52228b8SJoe Beteta skd_timer_tick(skd_device_t *skdev) 1033f52228b8SJoe Beteta { 1034f52228b8SJoe Beteta uint32_t timo_slot; 1035f52228b8SJoe Beteta 1036f52228b8SJoe Beteta skdev->timer_active = 1; 1037f52228b8SJoe Beteta 1038f52228b8SJoe Beteta if (skdev->state != SKD_DRVR_STATE_ONLINE) { 1039f52228b8SJoe Beteta skd_timer_tick_not_online(skdev); 1040f52228b8SJoe Beteta goto timer_func_out; 1041f52228b8SJoe Beteta } 1042f52228b8SJoe Beteta 1043f52228b8SJoe Beteta skdev->timeout_stamp++; 1044f52228b8SJoe Beteta timo_slot = skdev->timeout_stamp & SKD_TIMEOUT_SLOT_MASK; 1045f52228b8SJoe Beteta 1046f52228b8SJoe Beteta /* 1047f52228b8SJoe Beteta * All requests that happened during the previous use of 1048f52228b8SJoe Beteta * this slot should be done by now. The previous use was 1049f52228b8SJoe Beteta * over 7 seconds ago. 1050f52228b8SJoe Beteta */ 1051f52228b8SJoe Beteta if (skdev->timeout_slot[timo_slot] == 0) { 1052f52228b8SJoe Beteta goto timer_func_out; 1053f52228b8SJoe Beteta } 1054f52228b8SJoe Beteta 1055f52228b8SJoe Beteta /* Something is overdue */ 1056f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "found %d timeouts, draining busy=%d", 1057f52228b8SJoe Beteta skdev->timeout_slot[timo_slot], 1058f52228b8SJoe Beteta skdev->queue_depth_busy); 1059f52228b8SJoe Beteta skdev->timer_countdown = SKD_TIMER_SECONDS(3); 1060f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_DRAINING_TIMEOUT; 1061f52228b8SJoe Beteta skdev->timo_slot = timo_slot; 1062f52228b8SJoe Beteta 1063f52228b8SJoe Beteta timer_func_out: 1064f52228b8SJoe Beteta skdev->timer_active = 0; 1065f52228b8SJoe Beteta } 1066f52228b8SJoe Beteta 1067f52228b8SJoe Beteta /* 1068f52228b8SJoe Beteta * 1069f52228b8SJoe Beteta * Name: skd_timer_tick_not_online, handles various device 1070f52228b8SJoe Beteta * state transitions. 1071f52228b8SJoe Beteta * 1072f52228b8SJoe Beteta * Inputs: skdev - device state structure. 1073f52228b8SJoe Beteta * 1074f52228b8SJoe Beteta * Returns: Nothing. 1075f52228b8SJoe Beteta * 1076f52228b8SJoe Beteta */ 1077f52228b8SJoe Beteta static void 1078f52228b8SJoe Beteta skd_timer_tick_not_online(struct skd_device *skdev) 1079f52228b8SJoe Beteta { 1080f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "skd_skd_timer_tick_not_online: state=%d tmo=%d", 1081f52228b8SJoe Beteta skdev->state, skdev->timer_countdown); 1082f52228b8SJoe Beteta 1083f52228b8SJoe Beteta ASSERT(skdev->state != SKD_DRVR_STATE_ONLINE); 1084f52228b8SJoe Beteta 1085f52228b8SJoe Beteta switch (skdev->state) { 1086f52228b8SJoe Beteta case SKD_DRVR_STATE_IDLE: 1087f52228b8SJoe Beteta case SKD_DRVR_STATE_LOAD: 1088f52228b8SJoe Beteta break; 1089f52228b8SJoe Beteta case SKD_DRVR_STATE_BUSY_SANITIZE: 1090f52228b8SJoe Beteta cmn_err(CE_WARN, "!drive busy sanitize[%x], driver[%x]\n", 1091f52228b8SJoe Beteta skdev->drive_state, skdev->state); 1092f52228b8SJoe Beteta break; 1093f52228b8SJoe Beteta 1094f52228b8SJoe Beteta case SKD_DRVR_STATE_BUSY: 1095f52228b8SJoe Beteta case SKD_DRVR_STATE_BUSY_IMMINENT: 1096f52228b8SJoe Beteta case SKD_DRVR_STATE_BUSY_ERASE: 1097f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "busy[%x], countdown=%d\n", 1098f52228b8SJoe Beteta skdev->state, skdev->timer_countdown); 1099f52228b8SJoe Beteta if (skdev->timer_countdown > 0) { 1100f52228b8SJoe Beteta skdev->timer_countdown--; 1101f52228b8SJoe Beteta return; 1102f52228b8SJoe Beteta } 1103f52228b8SJoe Beteta cmn_err(CE_WARN, "!busy[%x], timedout=%d, restarting device.", 1104f52228b8SJoe Beteta skdev->state, skdev->timer_countdown); 1105f52228b8SJoe Beteta skd_restart_device(skdev); 1106f52228b8SJoe Beteta break; 1107f52228b8SJoe Beteta 1108f52228b8SJoe Beteta case SKD_DRVR_STATE_WAIT_BOOT: 1109f52228b8SJoe Beteta case SKD_DRVR_STATE_STARTING: 1110f52228b8SJoe Beteta if (skdev->timer_countdown > 0) { 1111f52228b8SJoe Beteta skdev->timer_countdown--; 1112f52228b8SJoe Beteta return; 1113f52228b8SJoe Beteta } 1114f52228b8SJoe Beteta /* 1115f52228b8SJoe Beteta * For now, we fault the drive. Could attempt resets to 1116f52228b8SJoe Beteta * revcover at some point. 1117f52228b8SJoe Beteta */ 1118f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_FAULT; 1119f52228b8SJoe Beteta 1120f52228b8SJoe Beteta cmn_err(CE_WARN, "!(%s): DriveFault Connect Timeout (%x)", 1121f52228b8SJoe Beteta skd_name(skdev), skdev->drive_state); 1122f52228b8SJoe Beteta 1123f52228b8SJoe Beteta /* start the queue so we can respond with error to requests */ 1124f52228b8SJoe Beteta skd_start(skdev); 1125f52228b8SJoe Beteta 1126f52228b8SJoe Beteta /* wakeup anyone waiting for startup complete */ 1127f52228b8SJoe Beteta skdev->gendisk_on = -1; 1128f52228b8SJoe Beteta 1129f52228b8SJoe Beteta cv_signal(&skdev->cv_waitq); 1130f52228b8SJoe Beteta break; 1131f52228b8SJoe Beteta 1132f52228b8SJoe Beteta 1133f52228b8SJoe Beteta case SKD_DRVR_STATE_PAUSING: 1134f52228b8SJoe Beteta case SKD_DRVR_STATE_PAUSED: 1135f52228b8SJoe Beteta break; 1136f52228b8SJoe Beteta 1137f52228b8SJoe Beteta case SKD_DRVR_STATE_DRAINING_TIMEOUT: 1138f52228b8SJoe Beteta cmn_err(CE_WARN, 1139f52228b8SJoe Beteta "!%s: draining busy [%d] tick[%d] qdb[%d] tmls[%d]\n", 1140f52228b8SJoe Beteta skdev->name, 1141f52228b8SJoe Beteta skdev->timo_slot, 1142f52228b8SJoe Beteta skdev->timer_countdown, 1143f52228b8SJoe Beteta skdev->queue_depth_busy, 1144f52228b8SJoe Beteta skdev->timeout_slot[skdev->timo_slot]); 1145f52228b8SJoe Beteta /* if the slot has cleared we can let the I/O continue */ 1146f52228b8SJoe Beteta if (skdev->timeout_slot[skdev->timo_slot] == 0) { 1147f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "Slot drained, starting queue."); 1148f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_ONLINE; 1149f52228b8SJoe Beteta skd_start(skdev); 1150f52228b8SJoe Beteta return; 1151f52228b8SJoe Beteta } 1152f52228b8SJoe Beteta if (skdev->timer_countdown > 0) { 1153f52228b8SJoe Beteta skdev->timer_countdown--; 1154f52228b8SJoe Beteta return; 1155f52228b8SJoe Beteta } 1156f52228b8SJoe Beteta skd_restart_device(skdev); 1157f52228b8SJoe Beteta break; 1158f52228b8SJoe Beteta 1159f52228b8SJoe Beteta case SKD_DRVR_STATE_RESTARTING: 1160f52228b8SJoe Beteta if (skdev->timer_countdown > 0) { 1161f52228b8SJoe Beteta skdev->timer_countdown--; 1162f52228b8SJoe Beteta 1163f52228b8SJoe Beteta return; 1164f52228b8SJoe Beteta } 1165f52228b8SJoe Beteta /* 1166f52228b8SJoe Beteta * For now, we fault the drive. Could attempt resets to 1167f52228b8SJoe Beteta * revcover at some point. 1168f52228b8SJoe Beteta */ 1169f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_FAULT; 1170f52228b8SJoe Beteta cmn_err(CE_WARN, "!(%s): DriveFault Reconnect Timeout (%x)\n", 1171f52228b8SJoe Beteta skd_name(skdev), skdev->drive_state); 1172f52228b8SJoe Beteta 1173f52228b8SJoe Beteta /* 1174f52228b8SJoe Beteta * Recovering does two things: 1175f52228b8SJoe Beteta * 1. completes IO with error 1176f52228b8SJoe Beteta * 2. reclaims dma resources 1177f52228b8SJoe Beteta * When is it safe to recover requests? 1178f52228b8SJoe Beteta * - if the drive state is faulted 1179f52228b8SJoe Beteta * - if the state is still soft reset after out timeout 1180f52228b8SJoe Beteta * - if the drive registers are dead (state = FF) 1181f52228b8SJoe Beteta */ 1182f52228b8SJoe Beteta 1183f52228b8SJoe Beteta if ((skdev->drive_state == FIT_SR_DRIVE_SOFT_RESET) || 1184f52228b8SJoe Beteta (skdev->drive_state == FIT_SR_DRIVE_FAULT) || 1185f52228b8SJoe Beteta (skdev->drive_state == FIT_SR_DRIVE_STATE_MASK)) { 1186f52228b8SJoe Beteta /* 1187f52228b8SJoe Beteta * It never came out of soft reset. Try to 1188f52228b8SJoe Beteta * recover the requests and then let them 1189f52228b8SJoe Beteta * fail. This is to mitigate hung processes. 1190f52228b8SJoe Beteta * 1191f52228b8SJoe Beteta * Acquire the interrupt lock since these lists are 1192f52228b8SJoe Beteta * manipulated by interrupt handlers. 1193f52228b8SJoe Beteta */ 1194f52228b8SJoe Beteta ASSERT(!WAITQ_LOCK_HELD(skdev)); 1195f52228b8SJoe Beteta INTR_LOCK(skdev); 1196f52228b8SJoe Beteta skd_recover_requests(skdev); 1197f52228b8SJoe Beteta INTR_UNLOCK(skdev); 1198f52228b8SJoe Beteta } 1199f52228b8SJoe Beteta /* start the queue so we can respond with error to requests */ 1200f52228b8SJoe Beteta skd_start(skdev); 1201f52228b8SJoe Beteta /* wakeup anyone waiting for startup complete */ 1202f52228b8SJoe Beteta skdev->gendisk_on = -1; 1203f52228b8SJoe Beteta cv_signal(&skdev->cv_waitq); 1204f52228b8SJoe Beteta break; 1205f52228b8SJoe Beteta 1206f52228b8SJoe Beteta case SKD_DRVR_STATE_RESUMING: 1207f52228b8SJoe Beteta case SKD_DRVR_STATE_STOPPING: 1208f52228b8SJoe Beteta case SKD_DRVR_STATE_SYNCING: 1209f52228b8SJoe Beteta case SKD_DRVR_STATE_FAULT: 1210f52228b8SJoe Beteta case SKD_DRVR_STATE_DISAPPEARED: 1211f52228b8SJoe Beteta default: 1212f52228b8SJoe Beteta break; 1213f52228b8SJoe Beteta } 1214f52228b8SJoe Beteta } 1215f52228b8SJoe Beteta 1216f52228b8SJoe Beteta /* 1217f52228b8SJoe Beteta * 1218f52228b8SJoe Beteta * Name: skd_timer, kicks off the timer processing. 1219f52228b8SJoe Beteta * 1220f52228b8SJoe Beteta * Inputs: skdev - device state structure. 1221f52228b8SJoe Beteta * 1222f52228b8SJoe Beteta * Returns: Nothing. 1223f52228b8SJoe Beteta * 1224f52228b8SJoe Beteta */ 1225f52228b8SJoe Beteta static void 1226f52228b8SJoe Beteta skd_timer(void *arg) 1227f52228b8SJoe Beteta { 1228f52228b8SJoe Beteta skd_device_t *skdev = (skd_device_t *)arg; 1229f52228b8SJoe Beteta 1230f52228b8SJoe Beteta /* Someone set us to 0, don't bother rescheduling. */ 1231f52228b8SJoe Beteta ADAPTER_STATE_LOCK(skdev); 1232f52228b8SJoe Beteta if (skdev->skd_timer_timeout_id != 0) { 1233f52228b8SJoe Beteta ADAPTER_STATE_UNLOCK(skdev); 1234f52228b8SJoe Beteta /* Pardon the drop-and-then-acquire logic here. */ 1235f52228b8SJoe Beteta skd_timer_tick(skdev); 1236f52228b8SJoe Beteta ADAPTER_STATE_LOCK(skdev); 1237f52228b8SJoe Beteta /* Restart timer, if not being stopped. */ 1238f52228b8SJoe Beteta if (skdev->skd_timer_timeout_id != 0) { 1239f52228b8SJoe Beteta skdev->skd_timer_timeout_id = 1240f52228b8SJoe Beteta timeout(skd_timer, arg, skd_timer_ticks); 1241f52228b8SJoe Beteta } 1242f52228b8SJoe Beteta } 1243f52228b8SJoe Beteta ADAPTER_STATE_UNLOCK(skdev); 1244f52228b8SJoe Beteta } 1245f52228b8SJoe Beteta 1246f52228b8SJoe Beteta /* 1247f52228b8SJoe Beteta * 1248f52228b8SJoe Beteta * Name: skd_start_timer, kicks off the 1-second timer. 1249f52228b8SJoe Beteta * 1250f52228b8SJoe Beteta * Inputs: skdev - device state structure. 1251f52228b8SJoe Beteta * 1252f52228b8SJoe Beteta * Returns: Zero. 1253f52228b8SJoe Beteta * 1254f52228b8SJoe Beteta */ 1255f52228b8SJoe Beteta static void 1256f52228b8SJoe Beteta skd_start_timer(struct skd_device *skdev) 1257f52228b8SJoe Beteta { 1258f52228b8SJoe Beteta /* Start one second driver timer. */ 1259f52228b8SJoe Beteta ADAPTER_STATE_LOCK(skdev); 1260f52228b8SJoe Beteta ASSERT(skdev->skd_timer_timeout_id == 0); 1261f52228b8SJoe Beteta 1262f52228b8SJoe Beteta /* 1263f52228b8SJoe Beteta * Do first "timeout tick" right away, but not in this 1264f52228b8SJoe Beteta * thread. 1265f52228b8SJoe Beteta */ 1266f52228b8SJoe Beteta skdev->skd_timer_timeout_id = timeout(skd_timer, skdev, 1); 1267f52228b8SJoe Beteta ADAPTER_STATE_UNLOCK(skdev); 1268f52228b8SJoe Beteta } 1269f52228b8SJoe Beteta 1270f52228b8SJoe Beteta /* 1271f52228b8SJoe Beteta * INTERNAL REQUESTS -- generated by driver itself 1272f52228b8SJoe Beteta */ 1273f52228b8SJoe Beteta 1274f52228b8SJoe Beteta /* 1275f52228b8SJoe Beteta * 1276f52228b8SJoe Beteta * Name: skd_format_internal_skspcl, setups the internal 1277f52228b8SJoe Beteta * FIT request message. 1278f52228b8SJoe Beteta * 1279f52228b8SJoe Beteta * Inputs: skdev - device state structure. 1280f52228b8SJoe Beteta * 1281f52228b8SJoe Beteta * Returns: One. 1282f52228b8SJoe Beteta * 1283f52228b8SJoe Beteta */ 1284f52228b8SJoe Beteta static int 1285f52228b8SJoe Beteta skd_format_internal_skspcl(struct skd_device *skdev) 1286f52228b8SJoe Beteta { 1287f52228b8SJoe Beteta struct skd_special_context *skspcl = &skdev->internal_skspcl; 1288f52228b8SJoe Beteta struct fit_sg_descriptor *sgd = &skspcl->req.sksg_list[0]; 1289f52228b8SJoe Beteta struct fit_msg_hdr *fmh; 1290f52228b8SJoe Beteta uint64_t dma_address; 1291f52228b8SJoe Beteta struct skd_scsi_request *scsi; 1292f52228b8SJoe Beteta 1293f52228b8SJoe Beteta fmh = (struct fit_msg_hdr *)&skspcl->msg_buf64[0]; 1294f52228b8SJoe Beteta fmh->protocol_id = FIT_PROTOCOL_ID_SOFIT; 1295f52228b8SJoe Beteta fmh->num_protocol_cmds_coalesced = 1; 1296f52228b8SJoe Beteta 1297f52228b8SJoe Beteta /* Instead of 64-bytes in, use 8-(64-bit-words) for linted alignment. */ 1298f52228b8SJoe Beteta scsi = (struct skd_scsi_request *)&skspcl->msg_buf64[8]; 1299f52228b8SJoe Beteta bzero(scsi, sizeof (*scsi)); 1300f52228b8SJoe Beteta dma_address = skspcl->req.sksg_dma_address.cookies->_dmu._dmac_ll; 1301f52228b8SJoe Beteta scsi->hdr.sg_list_dma_address = cpu_to_be64(dma_address); 1302f52228b8SJoe Beteta sgd->control = FIT_SGD_CONTROL_LAST; 1303f52228b8SJoe Beteta sgd->byte_count = 0; 1304f52228b8SJoe Beteta sgd->host_side_addr = skspcl->db_dma_address.cookies->_dmu._dmac_ll; 1305f52228b8SJoe Beteta sgd->dev_side_addr = 0; /* not used */ 1306f52228b8SJoe Beteta sgd->next_desc_ptr = 0LL; 1307f52228b8SJoe Beteta 1308f52228b8SJoe Beteta return (1); 1309f52228b8SJoe Beteta } 1310f52228b8SJoe Beteta 1311f52228b8SJoe Beteta /* 1312f52228b8SJoe Beteta * 1313f52228b8SJoe Beteta * Name: skd_send_internal_skspcl, send internal requests to 1314f52228b8SJoe Beteta * the hardware. 1315f52228b8SJoe Beteta * 1316f52228b8SJoe Beteta * Inputs: skdev - device state structure. 1317f52228b8SJoe Beteta * skspcl - request structure 1318f52228b8SJoe Beteta * opcode - just what it says 1319f52228b8SJoe Beteta * 1320f52228b8SJoe Beteta * Returns: Nothing. 1321f52228b8SJoe Beteta * 1322f52228b8SJoe Beteta */ 1323f52228b8SJoe Beteta void 1324f52228b8SJoe Beteta skd_send_internal_skspcl(struct skd_device *skdev, 1325f52228b8SJoe Beteta struct skd_special_context *skspcl, uint8_t opcode) 1326f52228b8SJoe Beteta { 1327f52228b8SJoe Beteta struct fit_sg_descriptor *sgd = &skspcl->req.sksg_list[0]; 1328f52228b8SJoe Beteta struct skd_scsi_request *scsi; 1329f52228b8SJoe Beteta 1330f52228b8SJoe Beteta if (SKD_REQ_STATE_IDLE != skspcl->req.state) { 1331f52228b8SJoe Beteta /* 1332f52228b8SJoe Beteta * A refresh is already in progress. 1333f52228b8SJoe Beteta * Just wait for it to finish. 1334f52228b8SJoe Beteta */ 1335f52228b8SJoe Beteta return; 1336f52228b8SJoe Beteta } 1337f52228b8SJoe Beteta 1338f52228b8SJoe Beteta ASSERT(0 == (skspcl->req.id & SKD_ID_INCR)); 1339f52228b8SJoe Beteta skspcl->req.state = SKD_REQ_STATE_BUSY; 1340f52228b8SJoe Beteta skspcl->req.id += SKD_ID_INCR; 1341f52228b8SJoe Beteta 1342f52228b8SJoe Beteta /* Instead of 64-bytes in, use 8-(64-bit-words) for linted alignment. */ 1343f52228b8SJoe Beteta scsi = (struct skd_scsi_request *)&skspcl->msg_buf64[8]; 1344f52228b8SJoe Beteta scsi->hdr.tag = skspcl->req.id; 1345f52228b8SJoe Beteta 1346f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "internal skspcl: opcode=%x req.id=%x ==========>", 1347f52228b8SJoe Beteta opcode, skspcl->req.id); 1348f52228b8SJoe Beteta 1349f52228b8SJoe Beteta switch (opcode) { 1350f52228b8SJoe Beteta case TEST_UNIT_READY: 1351f52228b8SJoe Beteta scsi->cdb[0] = TEST_UNIT_READY; 1352f52228b8SJoe Beteta scsi->cdb[1] = 0x00; 1353f52228b8SJoe Beteta scsi->cdb[2] = 0x00; 1354f52228b8SJoe Beteta scsi->cdb[3] = 0x00; 1355f52228b8SJoe Beteta scsi->cdb[4] = 0x00; 1356f52228b8SJoe Beteta scsi->cdb[5] = 0x00; 1357f52228b8SJoe Beteta sgd->byte_count = 0; 1358f52228b8SJoe Beteta scsi->hdr.sg_list_len_bytes = 0; 1359f52228b8SJoe Beteta break; 1360f52228b8SJoe Beteta case READ_CAPACITY_EXT: 1361f52228b8SJoe Beteta scsi->cdb[0] = READ_CAPACITY_EXT; 1362f52228b8SJoe Beteta scsi->cdb[1] = 0x10; 1363f52228b8SJoe Beteta scsi->cdb[2] = 0x00; 1364f52228b8SJoe Beteta scsi->cdb[3] = 0x00; 1365f52228b8SJoe Beteta scsi->cdb[4] = 0x00; 1366f52228b8SJoe Beteta scsi->cdb[5] = 0x00; 1367f52228b8SJoe Beteta scsi->cdb[6] = 0x00; 1368f52228b8SJoe Beteta scsi->cdb[7] = 0x00; 1369f52228b8SJoe Beteta scsi->cdb[8] = 0x00; 1370f52228b8SJoe Beteta scsi->cdb[9] = 0x00; 1371f52228b8SJoe Beteta scsi->cdb[10] = 0x00; 1372f52228b8SJoe Beteta scsi->cdb[11] = 0x00; 1373f52228b8SJoe Beteta scsi->cdb[12] = 0x00; 1374f52228b8SJoe Beteta scsi->cdb[13] = 0x20; 1375f52228b8SJoe Beteta scsi->cdb[14] = 0x00; 1376f52228b8SJoe Beteta scsi->cdb[15] = 0x00; 1377f52228b8SJoe Beteta sgd->byte_count = SKD_N_READ_CAP_EXT_BYTES; 1378f52228b8SJoe Beteta scsi->hdr.sg_list_len_bytes = cpu_to_be32(sgd->byte_count); 1379f52228b8SJoe Beteta break; 1380f52228b8SJoe Beteta case 0x28: 1381f52228b8SJoe Beteta (void) memset(skspcl->data_buf, 0x65, SKD_N_INTERNAL_BYTES); 1382f52228b8SJoe Beteta 1383f52228b8SJoe Beteta scsi->cdb[0] = 0x28; 1384f52228b8SJoe Beteta scsi->cdb[1] = 0x00; 1385f52228b8SJoe Beteta scsi->cdb[2] = 0x00; 1386f52228b8SJoe Beteta scsi->cdb[3] = 0x00; 1387f52228b8SJoe Beteta scsi->cdb[4] = 0x00; 1388f52228b8SJoe Beteta scsi->cdb[5] = 0x00; 1389f52228b8SJoe Beteta scsi->cdb[6] = 0x00; 1390f52228b8SJoe Beteta scsi->cdb[7] = 0x00; 1391f52228b8SJoe Beteta scsi->cdb[8] = 0x01; 1392f52228b8SJoe Beteta scsi->cdb[9] = 0x00; 1393f52228b8SJoe Beteta sgd->byte_count = SKD_N_INTERNAL_BYTES; 1394f52228b8SJoe Beteta scsi->hdr.sg_list_len_bytes = cpu_to_be32(SKD_N_INTERNAL_BYTES); 1395f52228b8SJoe Beteta break; 1396f52228b8SJoe Beteta case INQUIRY: 1397f52228b8SJoe Beteta scsi->cdb[0] = INQUIRY; 1398f52228b8SJoe Beteta scsi->cdb[1] = 0x01; /* evpd */ 1399f52228b8SJoe Beteta scsi->cdb[2] = 0x80; /* serial number page */ 1400f52228b8SJoe Beteta scsi->cdb[3] = 0x00; 1401f52228b8SJoe Beteta scsi->cdb[4] = 0x10; 1402f52228b8SJoe Beteta scsi->cdb[5] = 0x00; 1403f52228b8SJoe Beteta sgd->byte_count = 16; /* SKD_N_INQ_BYTES */; 1404f52228b8SJoe Beteta scsi->hdr.sg_list_len_bytes = cpu_to_be32(sgd->byte_count); 1405f52228b8SJoe Beteta break; 1406f52228b8SJoe Beteta case INQUIRY2: 1407f52228b8SJoe Beteta scsi->cdb[0] = INQUIRY; 1408f52228b8SJoe Beteta scsi->cdb[1] = 0x00; 1409f52228b8SJoe Beteta scsi->cdb[2] = 0x00; /* serial number page */ 1410f52228b8SJoe Beteta scsi->cdb[3] = 0x00; 1411f52228b8SJoe Beteta scsi->cdb[4] = 0x24; 1412f52228b8SJoe Beteta scsi->cdb[5] = 0x00; 1413f52228b8SJoe Beteta sgd->byte_count = 36; /* SKD_N_INQ_BYTES */; 1414f52228b8SJoe Beteta scsi->hdr.sg_list_len_bytes = cpu_to_be32(sgd->byte_count); 1415f52228b8SJoe Beteta break; 1416f52228b8SJoe Beteta case SYNCHRONIZE_CACHE: 1417f52228b8SJoe Beteta scsi->cdb[0] = SYNCHRONIZE_CACHE; 1418f52228b8SJoe Beteta scsi->cdb[1] = 0x00; 1419f52228b8SJoe Beteta scsi->cdb[2] = 0x00; 1420f52228b8SJoe Beteta scsi->cdb[3] = 0x00; 1421f52228b8SJoe Beteta scsi->cdb[4] = 0x00; 1422f52228b8SJoe Beteta scsi->cdb[5] = 0x00; 1423f52228b8SJoe Beteta scsi->cdb[6] = 0x00; 1424f52228b8SJoe Beteta scsi->cdb[7] = 0x00; 1425f52228b8SJoe Beteta scsi->cdb[8] = 0x00; 1426f52228b8SJoe Beteta scsi->cdb[9] = 0x00; 1427f52228b8SJoe Beteta sgd->byte_count = 0; 1428f52228b8SJoe Beteta scsi->hdr.sg_list_len_bytes = 0; 1429f52228b8SJoe Beteta break; 1430f52228b8SJoe Beteta default: 1431f52228b8SJoe Beteta ASSERT("Don't know what to send"); 1432f52228b8SJoe Beteta return; 1433f52228b8SJoe Beteta 1434f52228b8SJoe Beteta } 1435f52228b8SJoe Beteta 1436f52228b8SJoe Beteta skd_send_special_fitmsg(skdev, skspcl); 1437f52228b8SJoe Beteta } 1438f52228b8SJoe Beteta 1439f52228b8SJoe Beteta /* 1440f52228b8SJoe Beteta * 1441f52228b8SJoe Beteta * Name: skd_refresh_device_data, sends a TUR command. 1442f52228b8SJoe Beteta * 1443f52228b8SJoe Beteta * Inputs: skdev - device state structure. 1444f52228b8SJoe Beteta * 1445f52228b8SJoe Beteta * Returns: Nothing. 1446f52228b8SJoe Beteta * 1447f52228b8SJoe Beteta */ 1448f52228b8SJoe Beteta static void 1449f52228b8SJoe Beteta skd_refresh_device_data(struct skd_device *skdev) 1450f52228b8SJoe Beteta { 1451f52228b8SJoe Beteta struct skd_special_context *skspcl = &skdev->internal_skspcl; 1452f52228b8SJoe Beteta 1453f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "refresh_device_data: state=%d", skdev->state); 1454f52228b8SJoe Beteta 1455f52228b8SJoe Beteta skd_send_internal_skspcl(skdev, skspcl, TEST_UNIT_READY); 1456f52228b8SJoe Beteta } 1457f52228b8SJoe Beteta 1458f52228b8SJoe Beteta /* 1459f52228b8SJoe Beteta * 1460f52228b8SJoe Beteta * Name: skd_complete_internal, handles the completion of 1461f52228b8SJoe Beteta * driver-initiated I/O requests. 1462f52228b8SJoe Beteta * 1463f52228b8SJoe Beteta * Inputs: skdev - device state structure. 1464f52228b8SJoe Beteta * skcomp - completion structure. 1465f52228b8SJoe Beteta * skerr - error structure. 1466f52228b8SJoe Beteta * skspcl - request structure. 1467f52228b8SJoe Beteta * 1468f52228b8SJoe Beteta * Returns: Nothing. 1469f52228b8SJoe Beteta * 1470f52228b8SJoe Beteta */ 1471f52228b8SJoe Beteta /* ARGSUSED */ /* Upstream common source with other platforms. */ 1472f52228b8SJoe Beteta static void 1473f52228b8SJoe Beteta skd_complete_internal(struct skd_device *skdev, 1474f52228b8SJoe Beteta volatile struct fit_completion_entry_v1 *skcomp, 1475f52228b8SJoe Beteta volatile struct fit_comp_error_info *skerr, 1476f52228b8SJoe Beteta struct skd_special_context *skspcl) 1477f52228b8SJoe Beteta { 1478f52228b8SJoe Beteta uint8_t *buf = skspcl->data_buf; 1479f52228b8SJoe Beteta uint8_t status = 2; 1480f52228b8SJoe Beteta /* Instead of 64-bytes in, use 8-(64-bit-words) for linted alignment. */ 1481f52228b8SJoe Beteta struct skd_scsi_request *scsi = 1482f52228b8SJoe Beteta (struct skd_scsi_request *)&skspcl->msg_buf64[8]; 1483f52228b8SJoe Beteta 1484f52228b8SJoe Beteta ASSERT(skspcl == &skdev->internal_skspcl); 1485f52228b8SJoe Beteta 1486f52228b8SJoe Beteta (void) ddi_dma_sync(skspcl->db_dma_address.dma_handle, 0, 0, 1487f52228b8SJoe Beteta DDI_DMA_SYNC_FORKERNEL); 1488f52228b8SJoe Beteta (void) ddi_dma_sync(skspcl->mb_dma_address.dma_handle, 0, 0, 1489f52228b8SJoe Beteta DDI_DMA_SYNC_FORKERNEL); 1490f52228b8SJoe Beteta 1491f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "complete internal %x", scsi->cdb[0]); 1492f52228b8SJoe Beteta 1493f52228b8SJoe Beteta skspcl->req.completion = *skcomp; 1494f52228b8SJoe Beteta skspcl->req.state = SKD_REQ_STATE_IDLE; 1495f52228b8SJoe Beteta skspcl->req.id += SKD_ID_INCR; 1496f52228b8SJoe Beteta 1497f52228b8SJoe Beteta status = skspcl->req.completion.status; 1498f52228b8SJoe Beteta 1499f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "<<<<====== complete_internal: opc=%x", *scsi->cdb); 1500f52228b8SJoe Beteta 1501f52228b8SJoe Beteta switch (scsi->cdb[0]) { 1502f52228b8SJoe Beteta case TEST_UNIT_READY: 1503f52228b8SJoe Beteta if (SAM_STAT_GOOD == status) { 1504f52228b8SJoe Beteta skd_send_internal_skspcl(skdev, skspcl, 1505f52228b8SJoe Beteta READ_CAPACITY_EXT); 1506f52228b8SJoe Beteta } else { 1507f52228b8SJoe Beteta if (skdev->state == SKD_DRVR_STATE_STOPPING) { 1508f52228b8SJoe Beteta cmn_err(CE_WARN, 1509f52228b8SJoe Beteta "!%s: TUR failed, don't send anymore" 1510f52228b8SJoe Beteta "state 0x%x", skdev->name, skdev->state); 1511f52228b8SJoe Beteta 1512f52228b8SJoe Beteta return; 1513f52228b8SJoe Beteta } 1514f52228b8SJoe Beteta 1515f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "%s: TUR failed, retry skerr", 1516f52228b8SJoe Beteta skdev->name); 1517f52228b8SJoe Beteta skd_send_internal_skspcl(skdev, skspcl, 0x00); 1518f52228b8SJoe Beteta } 1519f52228b8SJoe Beteta break; 1520f52228b8SJoe Beteta case READ_CAPACITY_EXT: { 1521f52228b8SJoe Beteta uint64_t cap, Nblocks; 1522f52228b8SJoe Beteta uint64_t xbuf[1]; 1523f52228b8SJoe Beteta 1524f52228b8SJoe Beteta skdev->read_cap_is_valid = 0; 1525f52228b8SJoe Beteta if (SAM_STAT_GOOD == status) { 1526f52228b8SJoe Beteta bcopy(buf, xbuf, 8); 1527f52228b8SJoe Beteta cap = be64_to_cpu(*xbuf); 1528f52228b8SJoe Beteta skdev->read_cap_last_lba = cap; 1529f52228b8SJoe Beteta skdev->read_cap_blocksize = 1530f52228b8SJoe Beteta (buf[8] << 24) | (buf[9] << 16) | 1531f52228b8SJoe Beteta (buf[10] << 8) | buf[11]; 1532f52228b8SJoe Beteta 1533f52228b8SJoe Beteta cap *= skdev->read_cap_blocksize; 1534f52228b8SJoe Beteta Dcmn_err(CE_NOTE, " Last LBA: %" PRIu64 " (0x%" PRIx64 1535f52228b8SJoe Beteta "), blk sz: %d, Capacity: %" PRIu64 "GB\n", 1536f52228b8SJoe Beteta skdev->read_cap_last_lba, 1537f52228b8SJoe Beteta skdev->read_cap_last_lba, 1538f52228b8SJoe Beteta skdev->read_cap_blocksize, 1539f52228b8SJoe Beteta cap >> 30ULL); 1540f52228b8SJoe Beteta 1541f52228b8SJoe Beteta Nblocks = skdev->read_cap_last_lba + 1; 1542f52228b8SJoe Beteta 1543f52228b8SJoe Beteta skdev->Nblocks = Nblocks; 1544f52228b8SJoe Beteta skdev->read_cap_is_valid = 1; 1545f52228b8SJoe Beteta 1546f52228b8SJoe Beteta skd_send_internal_skspcl(skdev, skspcl, INQUIRY2); 1547f52228b8SJoe Beteta 1548f52228b8SJoe Beteta } else { 1549f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "**** READCAP failed, retry TUR"); 1550f52228b8SJoe Beteta skd_send_internal_skspcl(skdev, skspcl, 1551f52228b8SJoe Beteta TEST_UNIT_READY); 1552f52228b8SJoe Beteta } 1553f52228b8SJoe Beteta break; 1554f52228b8SJoe Beteta } 1555f52228b8SJoe Beteta case INQUIRY: 1556f52228b8SJoe Beteta skdev->inquiry_is_valid = 0; 1557f52228b8SJoe Beteta if (SAM_STAT_GOOD == status) { 1558f52228b8SJoe Beteta skdev->inquiry_is_valid = 1; 1559f52228b8SJoe Beteta 1560f52228b8SJoe Beteta if (scsi->cdb[1] == 0x1) { 1561f52228b8SJoe Beteta bcopy(&buf[4], skdev->inq_serial_num, 12); 1562f52228b8SJoe Beteta skdev->inq_serial_num[12] = '\0'; 1563f52228b8SJoe Beteta } else { 1564f52228b8SJoe Beteta char *tmp = skdev->inq_vendor_id; 1565f52228b8SJoe Beteta 1566f52228b8SJoe Beteta bcopy(&buf[8], tmp, 8); 1567f52228b8SJoe Beteta tmp[8] = '\0'; 1568f52228b8SJoe Beteta 1569f52228b8SJoe Beteta tmp = skdev->inq_product_id; 1570f52228b8SJoe Beteta bcopy(&buf[16], tmp, 16); 1571f52228b8SJoe Beteta tmp[16] = '\0'; 1572f52228b8SJoe Beteta 1573f52228b8SJoe Beteta tmp = skdev->inq_product_rev; 1574f52228b8SJoe Beteta bcopy(&buf[32], tmp, 4); 1575f52228b8SJoe Beteta tmp[4] = '\0'; 1576f52228b8SJoe Beteta } 1577f52228b8SJoe Beteta } 1578f52228b8SJoe Beteta 1579f52228b8SJoe Beteta if (skdev->state != SKD_DRVR_STATE_ONLINE) 1580f52228b8SJoe Beteta if (skd_unquiesce_dev(skdev) < 0) 1581f52228b8SJoe Beteta cmn_err(CE_NOTE, "** failed, to ONLINE device"); 1582f52228b8SJoe Beteta break; 1583f52228b8SJoe Beteta case SYNCHRONIZE_CACHE: 1584f52228b8SJoe Beteta skdev->sync_done = (SAM_STAT_GOOD == status) ? 1 : -1; 1585f52228b8SJoe Beteta 1586f52228b8SJoe Beteta cv_signal(&skdev->cv_waitq); 1587f52228b8SJoe Beteta break; 1588f52228b8SJoe Beteta 1589f52228b8SJoe Beteta default: 1590f52228b8SJoe Beteta ASSERT("we didn't send this"); 1591f52228b8SJoe Beteta } 1592f52228b8SJoe Beteta } 1593f52228b8SJoe Beteta 1594f52228b8SJoe Beteta /* 1595f52228b8SJoe Beteta * FIT MESSAGES 1596f52228b8SJoe Beteta */ 1597f52228b8SJoe Beteta 1598f52228b8SJoe Beteta /* 1599f52228b8SJoe Beteta * 1600f52228b8SJoe Beteta * Name: skd_send_fitmsg, send a FIT message to the hardware. 1601f52228b8SJoe Beteta * 1602f52228b8SJoe Beteta * Inputs: skdev - device state structure. 1603f52228b8SJoe Beteta * skmsg - FIT message structure. 1604f52228b8SJoe Beteta * 1605f52228b8SJoe Beteta * Returns: Nothing. 1606f52228b8SJoe Beteta * 1607f52228b8SJoe Beteta */ 1608f52228b8SJoe Beteta /* ARGSUSED */ /* Upstream common source with other platforms. */ 1609f52228b8SJoe Beteta static void 1610f52228b8SJoe Beteta skd_send_fitmsg(struct skd_device *skdev, 1611f52228b8SJoe Beteta struct skd_fitmsg_context *skmsg) 1612f52228b8SJoe Beteta { 1613f52228b8SJoe Beteta uint64_t qcmd; 1614f52228b8SJoe Beteta struct fit_msg_hdr *fmh; 1615f52228b8SJoe Beteta 1616f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "msgbuf's DMA addr: 0x%" PRIx64 ", qdepth_busy=%d", 1617f52228b8SJoe Beteta skmsg->mb_dma_address.cookies->dmac_laddress, 1618f52228b8SJoe Beteta skdev->queue_depth_busy); 1619f52228b8SJoe Beteta 1620f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "msg_buf 0x%p, offset %x", (void *)skmsg->msg_buf, 1621f52228b8SJoe Beteta skmsg->offset); 1622f52228b8SJoe Beteta 1623f52228b8SJoe Beteta qcmd = skmsg->mb_dma_address.cookies->dmac_laddress; 1624f52228b8SJoe Beteta qcmd |= FIT_QCMD_QID_NORMAL; 1625f52228b8SJoe Beteta 1626f52228b8SJoe Beteta fmh = (struct fit_msg_hdr *)skmsg->msg_buf64; 1627f52228b8SJoe Beteta skmsg->outstanding = fmh->num_protocol_cmds_coalesced; 1628f52228b8SJoe Beteta 1629f52228b8SJoe Beteta if (skdev->dbg_level > 1) { 1630f52228b8SJoe Beteta uint8_t *bp = skmsg->msg_buf; 1631f52228b8SJoe Beteta int i; 1632f52228b8SJoe Beteta 1633f52228b8SJoe Beteta for (i = 0; i < skmsg->length; i += 8) { 1634f52228b8SJoe Beteta Dcmn_err(CE_NOTE, " msg[%2d] %02x %02x %02x %02x " 1635f52228b8SJoe Beteta "%02x %02x %02x %02x", 1636f52228b8SJoe Beteta i, bp[i + 0], bp[i + 1], bp[i + 2], 1637f52228b8SJoe Beteta bp[i + 3], bp[i + 4], bp[i + 5], 1638f52228b8SJoe Beteta bp[i + 6], bp[i + 7]); 1639f52228b8SJoe Beteta if (i == 0) i = 64 - 8; 1640f52228b8SJoe Beteta } 1641f52228b8SJoe Beteta } 1642f52228b8SJoe Beteta 1643f52228b8SJoe Beteta (void) ddi_dma_sync(skmsg->mb_dma_address.dma_handle, 0, 0, 1644f52228b8SJoe Beteta DDI_DMA_SYNC_FORDEV); 1645f52228b8SJoe Beteta 1646f52228b8SJoe Beteta ASSERT(skmsg->length > sizeof (struct fit_msg_hdr)); 1647f52228b8SJoe Beteta if (skmsg->length > 256) { 1648f52228b8SJoe Beteta qcmd |= FIT_QCMD_MSGSIZE_512; 1649f52228b8SJoe Beteta } else if (skmsg->length > 128) { 1650f52228b8SJoe Beteta qcmd |= FIT_QCMD_MSGSIZE_256; 1651f52228b8SJoe Beteta } else if (skmsg->length > 64) { 1652f52228b8SJoe Beteta qcmd |= FIT_QCMD_MSGSIZE_128; 1653f52228b8SJoe Beteta } 1654f52228b8SJoe Beteta 1655f52228b8SJoe Beteta skdev->ios_started++; 1656f52228b8SJoe Beteta 1657f52228b8SJoe Beteta SKD_WRITEQ(skdev, qcmd, FIT_Q_COMMAND); 1658f52228b8SJoe Beteta } 1659f52228b8SJoe Beteta 1660f52228b8SJoe Beteta /* 1661f52228b8SJoe Beteta * 1662f52228b8SJoe Beteta * Name: skd_send_special_fitmsg, send a special FIT message 1663f52228b8SJoe Beteta * to the hardware used driver-originated I/O requests. 1664f52228b8SJoe Beteta * 1665f52228b8SJoe Beteta * Inputs: skdev - device state structure. 1666f52228b8SJoe Beteta * skspcl - skspcl structure. 1667f52228b8SJoe Beteta * 1668f52228b8SJoe Beteta * Returns: Nothing. 1669f52228b8SJoe Beteta * 1670f52228b8SJoe Beteta */ 1671f52228b8SJoe Beteta static void 1672f52228b8SJoe Beteta skd_send_special_fitmsg(struct skd_device *skdev, 1673f52228b8SJoe Beteta struct skd_special_context *skspcl) 1674f52228b8SJoe Beteta { 1675f52228b8SJoe Beteta uint64_t qcmd; 1676f52228b8SJoe Beteta 1677f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "send_special_fitmsg: pt 1"); 1678f52228b8SJoe Beteta 1679f52228b8SJoe Beteta if (skdev->dbg_level > 1) { 1680f52228b8SJoe Beteta uint8_t *bp = skspcl->msg_buf; 1681f52228b8SJoe Beteta int i; 1682f52228b8SJoe Beteta 1683f52228b8SJoe Beteta for (i = 0; i < SKD_N_SPECIAL_FITMSG_BYTES; i += 8) { 1684f52228b8SJoe Beteta cmn_err(CE_NOTE, 1685f52228b8SJoe Beteta " spcl[%2d] %02x %02x %02x %02x " 1686f52228b8SJoe Beteta "%02x %02x %02x %02x\n", i, 1687f52228b8SJoe Beteta bp[i + 0], bp[i + 1], bp[i + 2], bp[i + 3], 1688f52228b8SJoe Beteta bp[i + 4], bp[i + 5], bp[i + 6], bp[i + 7]); 1689f52228b8SJoe Beteta if (i == 0) i = 64 - 8; 1690f52228b8SJoe Beteta } 1691f52228b8SJoe Beteta 1692f52228b8SJoe Beteta for (i = 0; i < skspcl->req.n_sg; i++) { 1693f52228b8SJoe Beteta struct fit_sg_descriptor *sgd = 1694f52228b8SJoe Beteta &skspcl->req.sksg_list[i]; 1695f52228b8SJoe Beteta 1696f52228b8SJoe Beteta cmn_err(CE_NOTE, " sg[%d] count=%u ctrl=0x%x " 1697f52228b8SJoe Beteta "addr=0x%" PRIx64 " next=0x%" PRIx64, 1698f52228b8SJoe Beteta i, sgd->byte_count, sgd->control, 1699f52228b8SJoe Beteta sgd->host_side_addr, sgd->next_desc_ptr); 1700f52228b8SJoe Beteta } 1701f52228b8SJoe Beteta } 1702f52228b8SJoe Beteta 1703f52228b8SJoe Beteta (void) ddi_dma_sync(skspcl->mb_dma_address.dma_handle, 0, 0, 1704f52228b8SJoe Beteta DDI_DMA_SYNC_FORDEV); 1705f52228b8SJoe Beteta (void) ddi_dma_sync(skspcl->db_dma_address.dma_handle, 0, 0, 1706f52228b8SJoe Beteta DDI_DMA_SYNC_FORDEV); 1707f52228b8SJoe Beteta 1708f52228b8SJoe Beteta /* 1709f52228b8SJoe Beteta * Special FIT msgs are always 128 bytes: a 64-byte FIT hdr 1710f52228b8SJoe Beteta * and one 64-byte SSDI command. 1711f52228b8SJoe Beteta */ 1712f52228b8SJoe Beteta qcmd = skspcl->mb_dma_address.cookies->dmac_laddress; 1713f52228b8SJoe Beteta 1714f52228b8SJoe Beteta qcmd |= FIT_QCMD_QID_NORMAL + FIT_QCMD_MSGSIZE_128; 1715f52228b8SJoe Beteta 1716f52228b8SJoe Beteta SKD_WRITEQ(skdev, qcmd, FIT_Q_COMMAND); 1717f52228b8SJoe Beteta } 1718f52228b8SJoe Beteta 1719f52228b8SJoe Beteta /* 1720f52228b8SJoe Beteta * COMPLETION QUEUE 1721f52228b8SJoe Beteta */ 1722f52228b8SJoe Beteta 1723f52228b8SJoe Beteta static void skd_complete_other(struct skd_device *skdev, 1724f52228b8SJoe Beteta volatile struct fit_completion_entry_v1 *skcomp, 1725f52228b8SJoe Beteta volatile struct fit_comp_error_info *skerr); 1726f52228b8SJoe Beteta 1727f52228b8SJoe Beteta struct sns_info { 1728f52228b8SJoe Beteta uint8_t type; 1729f52228b8SJoe Beteta uint8_t stat; 1730f52228b8SJoe Beteta uint8_t key; 1731f52228b8SJoe Beteta uint8_t asc; 1732f52228b8SJoe Beteta uint8_t ascq; 1733f52228b8SJoe Beteta uint8_t mask; 1734f52228b8SJoe Beteta enum skd_check_status_action action; 1735f52228b8SJoe Beteta }; 1736f52228b8SJoe Beteta 1737f52228b8SJoe Beteta static struct sns_info skd_chkstat_table[] = { 1738f52228b8SJoe Beteta /* Good */ 1739f52228b8SJoe Beteta {0x70, 0x02, RECOVERED_ERROR, 0, 0, 0x1c, SKD_CHECK_STATUS_REPORT_GOOD}, 1740f52228b8SJoe Beteta 1741f52228b8SJoe Beteta /* Smart alerts */ 1742f52228b8SJoe Beteta {0x70, 0x02, NO_SENSE, 0x0B, 0x00, 0x1E, /* warnings */ 1743f52228b8SJoe Beteta SKD_CHECK_STATUS_REPORT_SMART_ALERT}, 1744f52228b8SJoe Beteta {0x70, 0x02, NO_SENSE, 0x5D, 0x00, 0x1E, /* thresholds */ 1745f52228b8SJoe Beteta SKD_CHECK_STATUS_REPORT_SMART_ALERT}, 1746f52228b8SJoe Beteta {0x70, 0x02, RECOVERED_ERROR, 0x0B, 0x01, 0x1F, /* temp over trigger */ 1747f52228b8SJoe Beteta SKD_CHECK_STATUS_REPORT_SMART_ALERT}, 1748f52228b8SJoe Beteta 1749f52228b8SJoe Beteta /* Retry (with limits) */ 1750f52228b8SJoe Beteta {0x70, 0x02, ABORTED_COMMAND, 0, 0, 0x1C, /* DMA errors */ 1751f52228b8SJoe Beteta SKD_CHECK_STATUS_REQUEUE_REQUEST}, 1752f52228b8SJoe Beteta {0x70, 0x02, UNIT_ATTENTION, 0x0B, 0x00, 0x1E, /* warnings */ 1753f52228b8SJoe Beteta SKD_CHECK_STATUS_REQUEUE_REQUEST}, 1754f52228b8SJoe Beteta {0x70, 0x02, UNIT_ATTENTION, 0x5D, 0x00, 0x1E, /* thresholds */ 1755f52228b8SJoe Beteta SKD_CHECK_STATUS_REQUEUE_REQUEST}, 1756f52228b8SJoe Beteta {0x70, 0x02, UNIT_ATTENTION, 0x80, 0x30, 0x1F, /* backup power */ 1757f52228b8SJoe Beteta SKD_CHECK_STATUS_REQUEUE_REQUEST}, 1758f52228b8SJoe Beteta 1759f52228b8SJoe Beteta /* Busy (or about to be) */ 1760f52228b8SJoe Beteta {0x70, 0x02, UNIT_ATTENTION, 0x3f, 0x01, 0x1F, /* fw changed */ 1761f52228b8SJoe Beteta SKD_CHECK_STATUS_BUSY_IMMINENT}, 1762f52228b8SJoe Beteta }; 1763f52228b8SJoe Beteta 1764f52228b8SJoe Beteta /* 1765f52228b8SJoe Beteta * 1766f52228b8SJoe Beteta * Name: skd_check_status, checks the return status from a 1767f52228b8SJoe Beteta * completed I/O request. 1768f52228b8SJoe Beteta * 1769f52228b8SJoe Beteta * Inputs: skdev - device state structure. 1770f52228b8SJoe Beteta * cmp_status - SCSI status byte. 1771f52228b8SJoe Beteta * skerr - the error data structure. 1772f52228b8SJoe Beteta * 1773f52228b8SJoe Beteta * Returns: Depending on the error condition, return the action 1774f52228b8SJoe Beteta * to be taken as specified in the skd_chkstat_table. 1775f52228b8SJoe Beteta * If no corresponding value is found in the table 1776f52228b8SJoe Beteta * return SKD_CHECK_STATUS_REPORT_GOOD is no error otherwise 1777f52228b8SJoe Beteta * return SKD_CHECK_STATUS_REPORT_ERROR. 1778f52228b8SJoe Beteta * 1779f52228b8SJoe Beteta */ 1780f52228b8SJoe Beteta static enum skd_check_status_action 1781f52228b8SJoe Beteta skd_check_status(struct skd_device *skdev, uint8_t cmp_status, 1782f52228b8SJoe Beteta volatile struct fit_comp_error_info *skerr) 1783f52228b8SJoe Beteta { 1784f52228b8SJoe Beteta /* 1785f52228b8SJoe Beteta * Look up status and sense data to decide how to handle the error 1786f52228b8SJoe Beteta * from the device. 1787f52228b8SJoe Beteta * mask says which fields must match e.g., mask=0x18 means check 1788f52228b8SJoe Beteta * type and stat, ignore key, asc, ascq. 1789f52228b8SJoe Beteta */ 1790f52228b8SJoe Beteta int i, n; 1791f52228b8SJoe Beteta 1792f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "(%s): key/asc/ascq %02x/%02x/%02x", 1793f52228b8SJoe Beteta skd_name(skdev), skerr->key, skerr->code, skerr->qual); 1794f52228b8SJoe Beteta 1795f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "stat: t=%02x stat=%02x k=%02x c=%02x q=%02x", 1796f52228b8SJoe Beteta skerr->type, cmp_status, skerr->key, skerr->code, skerr->qual); 1797f52228b8SJoe Beteta 1798f52228b8SJoe Beteta /* Does the info match an entry in the good category? */ 1799f52228b8SJoe Beteta n = sizeof (skd_chkstat_table) / sizeof (skd_chkstat_table[0]); 1800f52228b8SJoe Beteta for (i = 0; i < n; i++) { 1801f52228b8SJoe Beteta struct sns_info *sns = &skd_chkstat_table[i]; 1802f52228b8SJoe Beteta 1803f52228b8SJoe Beteta if (sns->mask & 0x10) 1804f52228b8SJoe Beteta if (skerr->type != sns->type) continue; 1805f52228b8SJoe Beteta 1806f52228b8SJoe Beteta if (sns->mask & 0x08) 1807f52228b8SJoe Beteta if (cmp_status != sns->stat) continue; 1808f52228b8SJoe Beteta 1809f52228b8SJoe Beteta if (sns->mask & 0x04) 1810f52228b8SJoe Beteta if (skerr->key != sns->key) continue; 1811f52228b8SJoe Beteta 1812f52228b8SJoe Beteta if (sns->mask & 0x02) 1813f52228b8SJoe Beteta if (skerr->code != sns->asc) continue; 1814f52228b8SJoe Beteta 1815f52228b8SJoe Beteta if (sns->mask & 0x01) 1816f52228b8SJoe Beteta if (skerr->qual != sns->ascq) continue; 1817f52228b8SJoe Beteta 1818f52228b8SJoe Beteta if (sns->action == SKD_CHECK_STATUS_REPORT_SMART_ALERT) { 1819f52228b8SJoe Beteta cmn_err(CE_WARN, "!(%s):SMART Alert: sense key/asc/ascq" 1820f52228b8SJoe Beteta " %02x/%02x/%02x", 1821f52228b8SJoe Beteta skd_name(skdev), skerr->key, 1822f52228b8SJoe Beteta skerr->code, skerr->qual); 1823f52228b8SJoe Beteta } 1824f52228b8SJoe Beteta 1825f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "skd_check_status: returning %x", 1826f52228b8SJoe Beteta sns->action); 1827f52228b8SJoe Beteta 1828f52228b8SJoe Beteta return (sns->action); 1829f52228b8SJoe Beteta } 1830f52228b8SJoe Beteta 1831f52228b8SJoe Beteta /* 1832f52228b8SJoe Beteta * No other match, so nonzero status means error, 1833f52228b8SJoe Beteta * zero status means good 1834f52228b8SJoe Beteta */ 1835f52228b8SJoe Beteta if (cmp_status) { 1836f52228b8SJoe Beteta cmn_err(CE_WARN, 1837f52228b8SJoe Beteta "!%s: status check: qdepth=%d skmfl=%p (%d) skrfl=%p (%d)", 1838f52228b8SJoe Beteta skdev->name, 1839f52228b8SJoe Beteta skdev->queue_depth_busy, 1840f52228b8SJoe Beteta (void *)skdev->skmsg_free_list, skd_list_skmsg(skdev, 0), 1841f52228b8SJoe Beteta (void *)skdev->skreq_free_list, skd_list_skreq(skdev, 0)); 1842f52228b8SJoe Beteta 1843f52228b8SJoe Beteta cmn_err(CE_WARN, "!%s: t=%02x stat=%02x k=%02x c=%02x q=%02x", 1844f52228b8SJoe Beteta skdev->name, skerr->type, cmp_status, skerr->key, 1845f52228b8SJoe Beteta skerr->code, skerr->qual); 1846f52228b8SJoe Beteta 1847f52228b8SJoe Beteta return (SKD_CHECK_STATUS_REPORT_ERROR); 1848f52228b8SJoe Beteta } 1849f52228b8SJoe Beteta 1850f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "status check good default"); 1851f52228b8SJoe Beteta 1852f52228b8SJoe Beteta return (SKD_CHECK_STATUS_REPORT_GOOD); 1853f52228b8SJoe Beteta } 1854f52228b8SJoe Beteta 1855f52228b8SJoe Beteta /* 1856f52228b8SJoe Beteta * 1857f52228b8SJoe Beteta * Name: skd_isr_completion_posted, handles I/O completions. 1858f52228b8SJoe Beteta * 1859f52228b8SJoe Beteta * Inputs: skdev - device state structure. 1860f52228b8SJoe Beteta * 1861f52228b8SJoe Beteta * Returns: Nothing. 1862f52228b8SJoe Beteta * 1863f52228b8SJoe Beteta */ 1864f52228b8SJoe Beteta static void 1865f52228b8SJoe Beteta skd_isr_completion_posted(struct skd_device *skdev) 1866f52228b8SJoe Beteta { 1867f52228b8SJoe Beteta volatile struct fit_completion_entry_v1 *skcmp = NULL; 1868f52228b8SJoe Beteta volatile struct fit_comp_error_info *skerr; 1869f52228b8SJoe Beteta struct skd_fitmsg_context *skmsg; 1870f52228b8SJoe Beteta struct skd_request_context *skreq; 1871f52228b8SJoe Beteta skd_buf_private_t *pbuf; 1872f52228b8SJoe Beteta uint16_t req_id; 1873f52228b8SJoe Beteta uint32_t req_slot; 1874f52228b8SJoe Beteta uint32_t timo_slot; 1875f52228b8SJoe Beteta uint32_t msg_slot; 1876f52228b8SJoe Beteta uint16_t cmp_cntxt = 0; 1877f52228b8SJoe Beteta uint8_t cmp_status = 0; 1878f52228b8SJoe Beteta uint8_t cmp_cycle = 0; 1879f52228b8SJoe Beteta uint32_t cmp_bytes = 0; 1880f52228b8SJoe Beteta 1881f52228b8SJoe Beteta (void) ddi_dma_sync(skdev->cq_dma_address.dma_handle, 0, 0, 1882f52228b8SJoe Beteta DDI_DMA_SYNC_FORKERNEL); 1883f52228b8SJoe Beteta 1884f52228b8SJoe Beteta for (;;) { 1885f52228b8SJoe Beteta ASSERT(skdev->skcomp_ix < SKD_N_COMPLETION_ENTRY); 1886f52228b8SJoe Beteta 1887f52228b8SJoe Beteta WAITQ_LOCK(skdev); 1888f52228b8SJoe Beteta 1889f52228b8SJoe Beteta skcmp = &skdev->skcomp_table[skdev->skcomp_ix]; 1890f52228b8SJoe Beteta cmp_cycle = skcmp->cycle; 1891f52228b8SJoe Beteta cmp_cntxt = skcmp->tag; 1892f52228b8SJoe Beteta cmp_status = skcmp->status; 1893f52228b8SJoe Beteta cmp_bytes = be32_to_cpu(skcmp->num_returned_bytes); 1894f52228b8SJoe Beteta 1895f52228b8SJoe Beteta skerr = &skdev->skerr_table[skdev->skcomp_ix]; 1896f52228b8SJoe Beteta 1897f52228b8SJoe Beteta Dcmn_err(CE_NOTE, 1898f52228b8SJoe Beteta "cycle=%d ix=%d got cycle=%d cmdctxt=0x%x stat=%d " 1899f52228b8SJoe Beteta "qdepth_busy=%d rbytes=0x%x proto=%d", 1900f52228b8SJoe Beteta skdev->skcomp_cycle, skdev->skcomp_ix, 1901f52228b8SJoe Beteta cmp_cycle, cmp_cntxt, cmp_status, 1902f52228b8SJoe Beteta skdev->queue_depth_busy, cmp_bytes, skdev->proto_ver); 1903f52228b8SJoe Beteta 1904f52228b8SJoe Beteta if (cmp_cycle != skdev->skcomp_cycle) { 1905f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "%s:end of completions", skdev->name); 1906f52228b8SJoe Beteta 1907f52228b8SJoe Beteta WAITQ_UNLOCK(skdev); 1908f52228b8SJoe Beteta break; 1909f52228b8SJoe Beteta } 1910f52228b8SJoe Beteta 1911f52228b8SJoe Beteta 1912f52228b8SJoe Beteta skdev->n_req++; 1913f52228b8SJoe Beteta 1914f52228b8SJoe Beteta /* 1915f52228b8SJoe Beteta * Update the completion queue head index and possibly 1916f52228b8SJoe Beteta * the completion cycle count. 1917f52228b8SJoe Beteta */ 1918f52228b8SJoe Beteta skdev->skcomp_ix++; 1919f52228b8SJoe Beteta if (skdev->skcomp_ix >= SKD_N_COMPLETION_ENTRY) { 1920f52228b8SJoe Beteta skdev->skcomp_ix = 0; 1921f52228b8SJoe Beteta skdev->skcomp_cycle++; /* 8-bit wrap-around */ 1922f52228b8SJoe Beteta } 1923f52228b8SJoe Beteta 1924f52228b8SJoe Beteta 1925f52228b8SJoe Beteta /* 1926f52228b8SJoe Beteta * The command context is a unique 32-bit ID. The low order 1927f52228b8SJoe Beteta * bits help locate the request. The request is usually a 1928f52228b8SJoe Beteta * r/w request (see skd_start() above) or a special request. 1929f52228b8SJoe Beteta */ 1930f52228b8SJoe Beteta req_id = cmp_cntxt; 1931f52228b8SJoe Beteta req_slot = req_id & SKD_ID_SLOT_AND_TABLE_MASK; 1932f52228b8SJoe Beteta 1933f52228b8SJoe Beteta Dcmn_err(CE_NOTE, 1934f52228b8SJoe Beteta "<<<< completion_posted 1: req_id=%x req_slot=%x", 1935f52228b8SJoe Beteta req_id, req_slot); 1936f52228b8SJoe Beteta 1937f52228b8SJoe Beteta /* Is this other than a r/w request? */ 1938f52228b8SJoe Beteta if (req_slot >= skdev->num_req_context) { 1939f52228b8SJoe Beteta /* 1940f52228b8SJoe Beteta * This is not a completion for a r/w request. 1941f52228b8SJoe Beteta */ 1942f52228b8SJoe Beteta skd_complete_other(skdev, skcmp, skerr); 1943f52228b8SJoe Beteta WAITQ_UNLOCK(skdev); 1944f52228b8SJoe Beteta continue; 1945f52228b8SJoe Beteta } 1946f52228b8SJoe Beteta 1947f52228b8SJoe Beteta skreq = &skdev->skreq_table[req_slot]; 1948f52228b8SJoe Beteta 1949f52228b8SJoe Beteta /* 1950f52228b8SJoe Beteta * Make sure the request ID for the slot matches. 1951f52228b8SJoe Beteta */ 1952f52228b8SJoe Beteta ASSERT(skreq->id == req_id); 1953f52228b8SJoe Beteta 1954f52228b8SJoe Beteta if (SKD_REQ_STATE_ABORTED == skreq->state) { 1955f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "reclaim req %p id=%04x\n", 1956f52228b8SJoe Beteta (void *)skreq, skreq->id); 1957f52228b8SJoe Beteta /* 1958f52228b8SJoe Beteta * a previously timed out command can 1959f52228b8SJoe Beteta * now be cleaned up 1960f52228b8SJoe Beteta */ 1961f52228b8SJoe Beteta msg_slot = skreq->fitmsg_id & SKD_ID_SLOT_MASK; 1962f52228b8SJoe Beteta ASSERT(msg_slot < skdev->num_fitmsg_context); 1963f52228b8SJoe Beteta skmsg = &skdev->skmsg_table[msg_slot]; 1964f52228b8SJoe Beteta if (skmsg->id == skreq->fitmsg_id) { 1965f52228b8SJoe Beteta ASSERT(skmsg->outstanding > 0); 1966f52228b8SJoe Beteta skmsg->outstanding--; 1967f52228b8SJoe Beteta if (skmsg->outstanding == 0) { 1968f52228b8SJoe Beteta ASSERT(SKD_MSG_STATE_BUSY == 1969f52228b8SJoe Beteta skmsg->state); 1970f52228b8SJoe Beteta skmsg->state = SKD_MSG_STATE_IDLE; 1971f52228b8SJoe Beteta skmsg->id += SKD_ID_INCR; 1972f52228b8SJoe Beteta skmsg->next = skdev->skmsg_free_list; 1973f52228b8SJoe Beteta skdev->skmsg_free_list = skmsg; 1974f52228b8SJoe Beteta } 1975f52228b8SJoe Beteta } 1976f52228b8SJoe Beteta /* 1977f52228b8SJoe Beteta * Reclaim the skd_request_context 1978f52228b8SJoe Beteta */ 1979f52228b8SJoe Beteta skreq->state = SKD_REQ_STATE_IDLE; 1980f52228b8SJoe Beteta skreq->id += SKD_ID_INCR; 1981f52228b8SJoe Beteta skreq->next = skdev->skreq_free_list; 1982f52228b8SJoe Beteta skdev->skreq_free_list = skreq; 1983f52228b8SJoe Beteta WAITQ_UNLOCK(skdev); 1984f52228b8SJoe Beteta continue; 1985f52228b8SJoe Beteta } 1986f52228b8SJoe Beteta 1987f52228b8SJoe Beteta skreq->completion.status = cmp_status; 1988f52228b8SJoe Beteta 1989f52228b8SJoe Beteta pbuf = skreq->pbuf; 1990f52228b8SJoe Beteta ASSERT(pbuf != NULL); 1991f52228b8SJoe Beteta 1992f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "<<<< completion_posted 2: pbuf=%p " 1993f52228b8SJoe Beteta "req_id=%x req_slot=%x", (void *)pbuf, req_id, req_slot); 1994f52228b8SJoe Beteta if (cmp_status && skdev->disks_initialized) { 1995f52228b8SJoe Beteta cmn_err(CE_WARN, "!%s: " 1996f52228b8SJoe Beteta "I/O err: pbuf=%p blkno=%lld (%llx) nbklks=%ld ", 1997f52228b8SJoe Beteta skdev->name, (void *)pbuf, pbuf->x_xfer->x_blkno, 1998f52228b8SJoe Beteta pbuf->x_xfer->x_blkno, pbuf->x_xfer->x_nblks); 1999f52228b8SJoe Beteta } 2000f52228b8SJoe Beteta 2001f52228b8SJoe Beteta ASSERT(skdev->active_cmds); 2002f52228b8SJoe Beteta atomic_dec_64(&skdev->active_cmds); 2003f52228b8SJoe Beteta 2004f52228b8SJoe Beteta if (SAM_STAT_GOOD == cmp_status) { 2005f52228b8SJoe Beteta /* Release DMA resources for the request. */ 2006f52228b8SJoe Beteta if (pbuf->x_xfer->x_nblks != 0) 2007f52228b8SJoe Beteta skd_blkdev_postop_sg_list(skdev, skreq); 2008f52228b8SJoe Beteta WAITQ_UNLOCK(skdev); 2009f52228b8SJoe Beteta skd_end_request(skdev, skreq, 0); 2010f52228b8SJoe Beteta WAITQ_LOCK(skdev); 2011f52228b8SJoe Beteta } else { 2012f52228b8SJoe Beteta switch (skd_check_status(skdev, cmp_status, skerr)) { 2013f52228b8SJoe Beteta case SKD_CHECK_STATUS_REPORT_GOOD: 2014f52228b8SJoe Beteta case SKD_CHECK_STATUS_REPORT_SMART_ALERT: 2015f52228b8SJoe Beteta WAITQ_UNLOCK(skdev); 2016f52228b8SJoe Beteta skd_end_request(skdev, skreq, 0); 2017f52228b8SJoe Beteta WAITQ_LOCK(skdev); 2018f52228b8SJoe Beteta break; 2019f52228b8SJoe Beteta 2020f52228b8SJoe Beteta case SKD_CHECK_STATUS_BUSY_IMMINENT: 2021f52228b8SJoe Beteta skd_log_skreq(skdev, skreq, "retry(busy)"); 2022f52228b8SJoe Beteta skd_queue(skdev, pbuf); 2023f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_BUSY_IMMINENT; 2024f52228b8SJoe Beteta skdev->timer_countdown = SKD_TIMER_MINUTES(20); 2025f52228b8SJoe Beteta 2026f52228b8SJoe Beteta (void) skd_quiesce_dev(skdev); 2027f52228b8SJoe Beteta break; 2028f52228b8SJoe Beteta 2029f52228b8SJoe Beteta /* FALLTHRU */ 2030f52228b8SJoe Beteta case SKD_CHECK_STATUS_REPORT_ERROR: 2031f52228b8SJoe Beteta /* fall thru to report error */ 2032f52228b8SJoe Beteta default: 2033f52228b8SJoe Beteta /* 2034f52228b8SJoe Beteta * Save the entire completion 2035f52228b8SJoe Beteta * and error entries for 2036f52228b8SJoe Beteta * later error interpretation. 2037f52228b8SJoe Beteta */ 2038f52228b8SJoe Beteta skreq->completion = *skcmp; 2039f52228b8SJoe Beteta skreq->err_info = *skerr; 2040f52228b8SJoe Beteta WAITQ_UNLOCK(skdev); 2041f52228b8SJoe Beteta skd_end_request(skdev, skreq, -EIO); 2042f52228b8SJoe Beteta WAITQ_LOCK(skdev); 2043f52228b8SJoe Beteta break; 2044f52228b8SJoe Beteta } 2045f52228b8SJoe Beteta } 2046f52228b8SJoe Beteta 2047f52228b8SJoe Beteta /* 2048f52228b8SJoe Beteta * Reclaim the FIT msg buffer if this is 2049f52228b8SJoe Beteta * the first of the requests it carried to 2050f52228b8SJoe Beteta * be completed. The FIT msg buffer used to 2051f52228b8SJoe Beteta * send this request cannot be reused until 2052f52228b8SJoe Beteta * we are sure the s1120 card has copied 2053f52228b8SJoe Beteta * it to its memory. The FIT msg might have 2054f52228b8SJoe Beteta * contained several requests. As soon as 2055f52228b8SJoe Beteta * any of them are completed we know that 2056f52228b8SJoe Beteta * the entire FIT msg was transferred. 2057f52228b8SJoe Beteta * Only the first completed request will 2058f52228b8SJoe Beteta * match the FIT msg buffer id. The FIT 2059f52228b8SJoe Beteta * msg buffer id is immediately updated. 2060f52228b8SJoe Beteta * When subsequent requests complete the FIT 2061f52228b8SJoe Beteta * msg buffer id won't match, so we know 2062f52228b8SJoe Beteta * quite cheaply that it is already done. 2063f52228b8SJoe Beteta */ 2064f52228b8SJoe Beteta msg_slot = skreq->fitmsg_id & SKD_ID_SLOT_MASK; 2065f52228b8SJoe Beteta 2066f52228b8SJoe Beteta ASSERT(msg_slot < skdev->num_fitmsg_context); 2067f52228b8SJoe Beteta skmsg = &skdev->skmsg_table[msg_slot]; 2068f52228b8SJoe Beteta if (skmsg->id == skreq->fitmsg_id) { 2069f52228b8SJoe Beteta ASSERT(SKD_MSG_STATE_BUSY == skmsg->state); 2070f52228b8SJoe Beteta skmsg->state = SKD_MSG_STATE_IDLE; 2071f52228b8SJoe Beteta skmsg->id += SKD_ID_INCR; 2072f52228b8SJoe Beteta skmsg->next = skdev->skmsg_free_list; 2073f52228b8SJoe Beteta skdev->skmsg_free_list = skmsg; 2074f52228b8SJoe Beteta } 2075f52228b8SJoe Beteta 2076f52228b8SJoe Beteta /* 2077f52228b8SJoe Beteta * Decrease the number of active requests. 2078f52228b8SJoe Beteta * This also decrements the count in the 2079f52228b8SJoe Beteta * timeout slot. 2080f52228b8SJoe Beteta */ 2081f52228b8SJoe Beteta timo_slot = skreq->timeout_stamp & SKD_TIMEOUT_SLOT_MASK; 2082f52228b8SJoe Beteta ASSERT(skdev->timeout_slot[timo_slot] > 0); 2083f52228b8SJoe Beteta ASSERT(skdev->queue_depth_busy > 0); 2084f52228b8SJoe Beteta 2085f52228b8SJoe Beteta atomic_dec_32(&skdev->timeout_slot[timo_slot]); 2086f52228b8SJoe Beteta atomic_dec_32(&skdev->queue_depth_busy); 2087f52228b8SJoe Beteta 2088f52228b8SJoe Beteta /* 2089f52228b8SJoe Beteta * Reclaim the skd_request_context 2090f52228b8SJoe Beteta */ 2091f52228b8SJoe Beteta skreq->state = SKD_REQ_STATE_IDLE; 2092f52228b8SJoe Beteta skreq->id += SKD_ID_INCR; 2093f52228b8SJoe Beteta skreq->next = skdev->skreq_free_list; 2094f52228b8SJoe Beteta skdev->skreq_free_list = skreq; 2095f52228b8SJoe Beteta 2096f52228b8SJoe Beteta WAITQ_UNLOCK(skdev); 2097f52228b8SJoe Beteta 2098f52228b8SJoe Beteta /* 2099f52228b8SJoe Beteta * make sure the lock is held by caller. 2100f52228b8SJoe Beteta */ 2101f52228b8SJoe Beteta if ((skdev->state == SKD_DRVR_STATE_PAUSING) && 2102f52228b8SJoe Beteta (0 == skdev->queue_depth_busy)) { 2103f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_PAUSED; 2104f52228b8SJoe Beteta cv_signal(&skdev->cv_waitq); 2105f52228b8SJoe Beteta } 2106f52228b8SJoe Beteta } /* for(;;) */ 2107f52228b8SJoe Beteta } 2108f52228b8SJoe Beteta 2109f52228b8SJoe Beteta /* 2110f52228b8SJoe Beteta * 2111f52228b8SJoe Beteta * Name: skd_complete_other, handle the completion of a 2112f52228b8SJoe Beteta * non-r/w request. 2113f52228b8SJoe Beteta * 2114f52228b8SJoe Beteta * Inputs: skdev - device state structure. 2115f52228b8SJoe Beteta * skcomp - FIT completion structure. 2116f52228b8SJoe Beteta * skerr - error structure. 2117f52228b8SJoe Beteta * 2118f52228b8SJoe Beteta * Returns: Nothing. 2119f52228b8SJoe Beteta * 2120f52228b8SJoe Beteta */ 2121f52228b8SJoe Beteta static void 2122f52228b8SJoe Beteta skd_complete_other(struct skd_device *skdev, 2123f52228b8SJoe Beteta volatile struct fit_completion_entry_v1 *skcomp, 2124f52228b8SJoe Beteta volatile struct fit_comp_error_info *skerr) 2125f52228b8SJoe Beteta { 2126f52228b8SJoe Beteta uint32_t req_id = 0; 2127f52228b8SJoe Beteta uint32_t req_table; 2128f52228b8SJoe Beteta uint32_t req_slot; 2129f52228b8SJoe Beteta struct skd_special_context *skspcl; 2130f52228b8SJoe Beteta 2131f52228b8SJoe Beteta req_id = skcomp->tag; 2132f52228b8SJoe Beteta req_table = req_id & SKD_ID_TABLE_MASK; 2133f52228b8SJoe Beteta req_slot = req_id & SKD_ID_SLOT_MASK; 2134f52228b8SJoe Beteta 2135f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "complete_other: table=0x%x id=0x%x slot=%d", 2136f52228b8SJoe Beteta req_table, req_id, req_slot); 2137f52228b8SJoe Beteta 2138f52228b8SJoe Beteta /* 2139f52228b8SJoe Beteta * Based on the request id, determine how to dispatch this completion. 2140f52228b8SJoe Beteta * This swich/case is finding the good cases and forwarding the 2141f52228b8SJoe Beteta * completion entry. Errors are reported below the switch. 2142f52228b8SJoe Beteta */ 2143f52228b8SJoe Beteta ASSERT(req_table == SKD_ID_INTERNAL); 2144f52228b8SJoe Beteta ASSERT(req_slot == 0); 2145f52228b8SJoe Beteta 2146f52228b8SJoe Beteta skspcl = &skdev->internal_skspcl; 2147f52228b8SJoe Beteta ASSERT(skspcl->req.id == req_id); 2148f52228b8SJoe Beteta ASSERT(skspcl->req.state == SKD_REQ_STATE_BUSY); 2149f52228b8SJoe Beteta 2150f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "<<<<== complete_other: ID_INTERNAL"); 2151f52228b8SJoe Beteta skd_complete_internal(skdev, skcomp, skerr, skspcl); 2152f52228b8SJoe Beteta } 2153f52228b8SJoe Beteta 2154f52228b8SJoe Beteta /* 2155f52228b8SJoe Beteta * 2156f52228b8SJoe Beteta * Name: skd_reset_skcomp, does what it says, resetting completion 2157f52228b8SJoe Beteta * tables. 2158f52228b8SJoe Beteta * 2159f52228b8SJoe Beteta * Inputs: skdev - device state structure. 2160f52228b8SJoe Beteta * 2161f52228b8SJoe Beteta * Returns: Nothing. 2162f52228b8SJoe Beteta * 2163f52228b8SJoe Beteta */ 2164f52228b8SJoe Beteta static void 2165f52228b8SJoe Beteta skd_reset_skcomp(struct skd_device *skdev) 2166f52228b8SJoe Beteta { 2167f52228b8SJoe Beteta uint32_t nbytes; 2168f52228b8SJoe Beteta 2169f52228b8SJoe Beteta nbytes = sizeof (struct fit_completion_entry_v1) * 2170f52228b8SJoe Beteta SKD_N_COMPLETION_ENTRY; 2171f52228b8SJoe Beteta nbytes += sizeof (struct fit_comp_error_info) * SKD_N_COMPLETION_ENTRY; 2172f52228b8SJoe Beteta 2173f52228b8SJoe Beteta if (skdev->skcomp_table) 2174f52228b8SJoe Beteta bzero(skdev->skcomp_table, nbytes); 2175f52228b8SJoe Beteta 2176f52228b8SJoe Beteta skdev->skcomp_ix = 0; 2177f52228b8SJoe Beteta skdev->skcomp_cycle = 1; 2178f52228b8SJoe Beteta } 2179f52228b8SJoe Beteta 2180f52228b8SJoe Beteta 2181f52228b8SJoe Beteta 2182f52228b8SJoe Beteta /* 2183f52228b8SJoe Beteta * INTERRUPTS 2184f52228b8SJoe Beteta */ 2185f52228b8SJoe Beteta 2186f52228b8SJoe Beteta /* 2187f52228b8SJoe Beteta * 2188f52228b8SJoe Beteta * Name: skd_isr_aif, handles the device interrupts. 2189f52228b8SJoe Beteta * 2190f52228b8SJoe Beteta * Inputs: arg - skdev device state structure. 2191f52228b8SJoe Beteta * intvec - not referenced 2192f52228b8SJoe Beteta * 2193f52228b8SJoe Beteta * Returns: DDI_INTR_CLAIMED if interrupt is handled otherwise 2194f52228b8SJoe Beteta * return DDI_INTR_UNCLAIMED. 2195f52228b8SJoe Beteta * 2196f52228b8SJoe Beteta */ 2197f52228b8SJoe Beteta /* ARGSUSED */ /* Upstream common source with other platforms. */ 2198f52228b8SJoe Beteta static uint_t 2199f52228b8SJoe Beteta skd_isr_aif(caddr_t arg, caddr_t intvec) 2200f52228b8SJoe Beteta { 2201f52228b8SJoe Beteta uint32_t intstat; 2202f52228b8SJoe Beteta uint32_t ack; 2203f52228b8SJoe Beteta int rc = DDI_INTR_UNCLAIMED; 2204f52228b8SJoe Beteta struct skd_device *skdev; 2205f52228b8SJoe Beteta 2206f52228b8SJoe Beteta skdev = (skd_device_t *)(uintptr_t)arg; 2207f52228b8SJoe Beteta 2208f52228b8SJoe Beteta ASSERT(skdev != NULL); 2209f52228b8SJoe Beteta 2210f52228b8SJoe Beteta skdev->intr_cntr++; 2211f52228b8SJoe Beteta 2212f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "skd_isr_aif: intr=%" PRId64 "\n", skdev->intr_cntr); 2213f52228b8SJoe Beteta 2214f52228b8SJoe Beteta for (;;) { 2215f52228b8SJoe Beteta 2216f52228b8SJoe Beteta ASSERT(!WAITQ_LOCK_HELD(skdev)); 2217f52228b8SJoe Beteta INTR_LOCK(skdev); 2218f52228b8SJoe Beteta 2219f52228b8SJoe Beteta intstat = SKD_READL(skdev, FIT_INT_STATUS_HOST); 2220f52228b8SJoe Beteta 2221f52228b8SJoe Beteta ack = FIT_INT_DEF_MASK; 2222f52228b8SJoe Beteta ack &= intstat; 2223f52228b8SJoe Beteta 2224f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "intstat=0x%x ack=0x%x", intstat, ack); 2225f52228b8SJoe Beteta 2226f52228b8SJoe Beteta /* 2227f52228b8SJoe Beteta * As long as there is an int pending on device, keep 2228f52228b8SJoe Beteta * running loop. When none, get out, but if we've never 2229f52228b8SJoe Beteta * done any processing, call completion handler? 2230f52228b8SJoe Beteta */ 2231f52228b8SJoe Beteta if (ack == 0) { 2232f52228b8SJoe Beteta /* 2233f52228b8SJoe Beteta * No interrupts on device, but run the completion 2234f52228b8SJoe Beteta * processor anyway? 2235f52228b8SJoe Beteta */ 2236f52228b8SJoe Beteta if (rc == DDI_INTR_UNCLAIMED && 2237f52228b8SJoe Beteta skdev->state == SKD_DRVR_STATE_ONLINE) { 2238f52228b8SJoe Beteta Dcmn_err(CE_NOTE, 2239f52228b8SJoe Beteta "1: Want isr_comp_posted call"); 2240f52228b8SJoe Beteta skd_isr_completion_posted(skdev); 2241f52228b8SJoe Beteta } 2242f52228b8SJoe Beteta INTR_UNLOCK(skdev); 2243f52228b8SJoe Beteta 2244f52228b8SJoe Beteta break; 2245f52228b8SJoe Beteta } 2246f52228b8SJoe Beteta rc = DDI_INTR_CLAIMED; 2247f52228b8SJoe Beteta 2248f52228b8SJoe Beteta SKD_WRITEL(skdev, ack, FIT_INT_STATUS_HOST); 2249f52228b8SJoe Beteta 2250f52228b8SJoe Beteta if ((skdev->state != SKD_DRVR_STATE_LOAD) && 2251f52228b8SJoe Beteta (skdev->state != SKD_DRVR_STATE_STOPPING)) { 2252f52228b8SJoe Beteta if (intstat & FIT_ISH_COMPLETION_POSTED) { 2253f52228b8SJoe Beteta Dcmn_err(CE_NOTE, 2254f52228b8SJoe Beteta "2: Want isr_comp_posted call"); 2255f52228b8SJoe Beteta skd_isr_completion_posted(skdev); 2256f52228b8SJoe Beteta } 2257f52228b8SJoe Beteta 2258f52228b8SJoe Beteta if (intstat & FIT_ISH_FW_STATE_CHANGE) { 2259f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "isr: fwstate change"); 2260f52228b8SJoe Beteta 2261f52228b8SJoe Beteta skd_isr_fwstate(skdev); 2262f52228b8SJoe Beteta if (skdev->state == SKD_DRVR_STATE_FAULT || 2263f52228b8SJoe Beteta skdev->state == 2264f52228b8SJoe Beteta SKD_DRVR_STATE_DISAPPEARED) { 2265f52228b8SJoe Beteta INTR_UNLOCK(skdev); 2266f52228b8SJoe Beteta 2267f52228b8SJoe Beteta return (rc); 2268f52228b8SJoe Beteta } 2269f52228b8SJoe Beteta } 2270f52228b8SJoe Beteta 2271f52228b8SJoe Beteta if (intstat & FIT_ISH_MSG_FROM_DEV) { 2272f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "isr: msg_from_dev change"); 2273f52228b8SJoe Beteta skd_isr_msg_from_dev(skdev); 2274f52228b8SJoe Beteta } 2275f52228b8SJoe Beteta } 2276f52228b8SJoe Beteta 2277f52228b8SJoe Beteta INTR_UNLOCK(skdev); 2278f52228b8SJoe Beteta } 2279f52228b8SJoe Beteta 2280f52228b8SJoe Beteta if (!SIMPLEQ_EMPTY(&skdev->waitqueue)) 2281f52228b8SJoe Beteta skd_start(skdev); 2282f52228b8SJoe Beteta 2283f52228b8SJoe Beteta return (rc); 2284f52228b8SJoe Beteta } 2285f52228b8SJoe Beteta 2286f52228b8SJoe Beteta /* 2287f52228b8SJoe Beteta * 2288f52228b8SJoe Beteta * Name: skd_drive_fault, set the drive state to DRV_STATE_FAULT. 2289f52228b8SJoe Beteta * 2290f52228b8SJoe Beteta * Inputs: skdev - device state structure. 2291f52228b8SJoe Beteta * 2292f52228b8SJoe Beteta * Returns: Nothing. 2293f52228b8SJoe Beteta * 2294f52228b8SJoe Beteta */ 2295f52228b8SJoe Beteta static void 2296f52228b8SJoe Beteta skd_drive_fault(struct skd_device *skdev) 2297f52228b8SJoe Beteta { 2298f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_FAULT; 2299f52228b8SJoe Beteta cmn_err(CE_WARN, "!(%s): Drive FAULT\n", 2300f52228b8SJoe Beteta skd_name(skdev)); 2301f52228b8SJoe Beteta } 2302f52228b8SJoe Beteta 2303f52228b8SJoe Beteta /* 2304f52228b8SJoe Beteta * 2305f52228b8SJoe Beteta * Name: skd_drive_disappeared, set the drive state to DISAPPEARED.. 2306f52228b8SJoe Beteta * 2307f52228b8SJoe Beteta * Inputs: skdev - device state structure. 2308f52228b8SJoe Beteta * 2309f52228b8SJoe Beteta * Returns: Nothing. 2310f52228b8SJoe Beteta * 2311f52228b8SJoe Beteta */ 2312f52228b8SJoe Beteta static void 2313f52228b8SJoe Beteta skd_drive_disappeared(struct skd_device *skdev) 2314f52228b8SJoe Beteta { 2315f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_DISAPPEARED; 2316f52228b8SJoe Beteta cmn_err(CE_WARN, "!(%s): Drive DISAPPEARED\n", 2317f52228b8SJoe Beteta skd_name(skdev)); 2318f52228b8SJoe Beteta } 2319f52228b8SJoe Beteta 2320f52228b8SJoe Beteta /* 2321f52228b8SJoe Beteta * 2322f52228b8SJoe Beteta * Name: skd_isr_fwstate, handles the various device states. 2323f52228b8SJoe Beteta * 2324f52228b8SJoe Beteta * Inputs: skdev - device state structure. 2325f52228b8SJoe Beteta * 2326f52228b8SJoe Beteta * Returns: Nothing. 2327f52228b8SJoe Beteta * 2328f52228b8SJoe Beteta */ 2329f52228b8SJoe Beteta static void 2330f52228b8SJoe Beteta skd_isr_fwstate(struct skd_device *skdev) 2331f52228b8SJoe Beteta { 2332f52228b8SJoe Beteta uint32_t sense; 2333f52228b8SJoe Beteta uint32_t state; 2334f52228b8SJoe Beteta int prev_driver_state; 2335f52228b8SJoe Beteta uint32_t mtd; 2336f52228b8SJoe Beteta 2337f52228b8SJoe Beteta prev_driver_state = skdev->state; 2338f52228b8SJoe Beteta 2339f52228b8SJoe Beteta sense = SKD_READL(skdev, FIT_STATUS); 2340f52228b8SJoe Beteta state = sense & FIT_SR_DRIVE_STATE_MASK; 2341f52228b8SJoe Beteta 2342f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "s1120 state %s(%d)=>%s(%d)", 2343f52228b8SJoe Beteta skd_drive_state_to_str(skdev->drive_state), skdev->drive_state, 2344f52228b8SJoe Beteta skd_drive_state_to_str(state), state); 2345f52228b8SJoe Beteta 2346f52228b8SJoe Beteta skdev->drive_state = state; 2347f52228b8SJoe Beteta 2348f52228b8SJoe Beteta switch (skdev->drive_state) { 2349f52228b8SJoe Beteta case FIT_SR_DRIVE_INIT: 2350f52228b8SJoe Beteta if (skdev->state == SKD_DRVR_STATE_PROTOCOL_MISMATCH) { 2351f52228b8SJoe Beteta skd_disable_interrupts(skdev); 2352f52228b8SJoe Beteta break; 2353f52228b8SJoe Beteta } 2354f52228b8SJoe Beteta if (skdev->state == SKD_DRVR_STATE_RESTARTING) { 2355f52228b8SJoe Beteta skd_recover_requests(skdev); 2356f52228b8SJoe Beteta } 2357f52228b8SJoe Beteta if (skdev->state == SKD_DRVR_STATE_WAIT_BOOT) { 2358f52228b8SJoe Beteta skdev->timer_countdown = 2359f52228b8SJoe Beteta SKD_TIMER_SECONDS(SKD_STARTING_TO); 2360f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_STARTING; 2361f52228b8SJoe Beteta skd_soft_reset(skdev); 2362f52228b8SJoe Beteta break; 2363f52228b8SJoe Beteta } 2364f52228b8SJoe Beteta mtd = FIT_MXD_CONS(FIT_MTD_FITFW_INIT, 0, 0); 2365f52228b8SJoe Beteta SKD_WRITEL(skdev, mtd, FIT_MSG_TO_DEVICE); 2366f52228b8SJoe Beteta skdev->last_mtd = mtd; 2367f52228b8SJoe Beteta break; 2368f52228b8SJoe Beteta 2369f52228b8SJoe Beteta case FIT_SR_DRIVE_ONLINE: 2370f52228b8SJoe Beteta skdev->queue_depth_limit = skdev->soft_queue_depth_limit; 2371f52228b8SJoe Beteta if (skdev->queue_depth_limit > skdev->hard_queue_depth_limit) { 2372f52228b8SJoe Beteta skdev->queue_depth_limit = 2373f52228b8SJoe Beteta skdev->hard_queue_depth_limit; 2374f52228b8SJoe Beteta } 2375f52228b8SJoe Beteta 2376f52228b8SJoe Beteta skdev->queue_depth_lowat = skdev->queue_depth_limit * 2 / 3 + 1; 2377f52228b8SJoe Beteta if (skdev->queue_depth_lowat < 1) 2378f52228b8SJoe Beteta skdev->queue_depth_lowat = 1; 2379f52228b8SJoe Beteta Dcmn_err(CE_NOTE, 2380f52228b8SJoe Beteta "%s queue depth limit=%d hard=%d soft=%d lowat=%d", 2381f52228b8SJoe Beteta DRV_NAME, 2382f52228b8SJoe Beteta skdev->queue_depth_limit, 2383f52228b8SJoe Beteta skdev->hard_queue_depth_limit, 2384f52228b8SJoe Beteta skdev->soft_queue_depth_limit, 2385f52228b8SJoe Beteta skdev->queue_depth_lowat); 2386f52228b8SJoe Beteta 2387f52228b8SJoe Beteta skd_refresh_device_data(skdev); 2388f52228b8SJoe Beteta break; 2389f52228b8SJoe Beteta case FIT_SR_DRIVE_BUSY: 2390f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_BUSY; 2391f52228b8SJoe Beteta skdev->timer_countdown = SKD_TIMER_MINUTES(20); 2392f52228b8SJoe Beteta (void) skd_quiesce_dev(skdev); 2393f52228b8SJoe Beteta break; 2394f52228b8SJoe Beteta case FIT_SR_DRIVE_BUSY_SANITIZE: 2395f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_BUSY_SANITIZE; 2396f52228b8SJoe Beteta skd_start(skdev); 2397f52228b8SJoe Beteta break; 2398f52228b8SJoe Beteta case FIT_SR_DRIVE_BUSY_ERASE: 2399f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_BUSY_ERASE; 2400f52228b8SJoe Beteta skdev->timer_countdown = SKD_TIMER_MINUTES(20); 2401f52228b8SJoe Beteta break; 2402f52228b8SJoe Beteta case FIT_SR_DRIVE_OFFLINE: 2403f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_IDLE; 2404f52228b8SJoe Beteta break; 2405f52228b8SJoe Beteta case FIT_SR_DRIVE_SOFT_RESET: 2406f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_RESTARTING; 2407f52228b8SJoe Beteta 2408f52228b8SJoe Beteta switch (skdev->state) { 2409f52228b8SJoe Beteta case SKD_DRVR_STATE_STARTING: 2410f52228b8SJoe Beteta case SKD_DRVR_STATE_RESTARTING: 2411f52228b8SJoe Beteta break; 2412f52228b8SJoe Beteta default: 2413f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_RESTARTING; 2414f52228b8SJoe Beteta break; 2415f52228b8SJoe Beteta } 2416f52228b8SJoe Beteta break; 2417f52228b8SJoe Beteta case FIT_SR_DRIVE_FW_BOOTING: 2418f52228b8SJoe Beteta Dcmn_err(CE_NOTE, 2419f52228b8SJoe Beteta "ISR FIT_SR_DRIVE_FW_BOOTING %s", skdev->name); 2420f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_WAIT_BOOT; 2421f52228b8SJoe Beteta skdev->timer_countdown = SKD_TIMER_SECONDS(SKD_WAIT_BOOT_TO); 2422f52228b8SJoe Beteta break; 2423f52228b8SJoe Beteta 2424f52228b8SJoe Beteta case FIT_SR_DRIVE_DEGRADED: 2425f52228b8SJoe Beteta case FIT_SR_PCIE_LINK_DOWN: 2426f52228b8SJoe Beteta case FIT_SR_DRIVE_NEED_FW_DOWNLOAD: 2427f52228b8SJoe Beteta break; 2428f52228b8SJoe Beteta 2429f52228b8SJoe Beteta case FIT_SR_DRIVE_FAULT: 2430f52228b8SJoe Beteta skd_drive_fault(skdev); 2431f52228b8SJoe Beteta skd_recover_requests(skdev); 2432f52228b8SJoe Beteta skd_start(skdev); 2433f52228b8SJoe Beteta break; 2434f52228b8SJoe Beteta 2435f52228b8SJoe Beteta case 0xFF: 2436f52228b8SJoe Beteta skd_drive_disappeared(skdev); 2437f52228b8SJoe Beteta skd_recover_requests(skdev); 2438f52228b8SJoe Beteta skd_start(skdev); 2439f52228b8SJoe Beteta break; 2440f52228b8SJoe Beteta default: 2441f52228b8SJoe Beteta /* 2442f52228b8SJoe Beteta * Uknown FW State. Wait for a state we recognize. 2443f52228b8SJoe Beteta */ 2444f52228b8SJoe Beteta break; 2445f52228b8SJoe Beteta } 2446f52228b8SJoe Beteta 2447f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "Driver state %s(%d)=>%s(%d)", 2448f52228b8SJoe Beteta skd_skdev_state_to_str(prev_driver_state), prev_driver_state, 2449f52228b8SJoe Beteta skd_skdev_state_to_str(skdev->state), skdev->state); 2450f52228b8SJoe Beteta } 2451f52228b8SJoe Beteta 2452f52228b8SJoe Beteta /* 2453f52228b8SJoe Beteta * 2454f52228b8SJoe Beteta * Name: skd_recover_requests, attempts to recover requests. 2455f52228b8SJoe Beteta * 2456f52228b8SJoe Beteta * Inputs: skdev - device state structure. 2457f52228b8SJoe Beteta * 2458f52228b8SJoe Beteta * Returns: Nothing. 2459f52228b8SJoe Beteta * 2460f52228b8SJoe Beteta */ 2461f52228b8SJoe Beteta static void 2462f52228b8SJoe Beteta skd_recover_requests(struct skd_device *skdev) 2463f52228b8SJoe Beteta { 2464f52228b8SJoe Beteta int i; 2465f52228b8SJoe Beteta 2466f52228b8SJoe Beteta ASSERT(INTR_LOCK_HELD(skdev)); 2467f52228b8SJoe Beteta 2468f52228b8SJoe Beteta for (i = 0; i < skdev->num_req_context; i++) { 2469f52228b8SJoe Beteta struct skd_request_context *skreq = &skdev->skreq_table[i]; 2470f52228b8SJoe Beteta 2471f52228b8SJoe Beteta if (skreq->state == SKD_REQ_STATE_BUSY) { 2472f52228b8SJoe Beteta skd_log_skreq(skdev, skreq, "requeue"); 2473f52228b8SJoe Beteta 2474f52228b8SJoe Beteta ASSERT(0 != (skreq->id & SKD_ID_INCR)); 2475f52228b8SJoe Beteta ASSERT(skreq->pbuf != NULL); 2476f52228b8SJoe Beteta /* Release DMA resources for the request. */ 2477f52228b8SJoe Beteta skd_blkdev_postop_sg_list(skdev, skreq); 2478f52228b8SJoe Beteta 2479f52228b8SJoe Beteta skd_end_request(skdev, skreq, EAGAIN); 2480f52228b8SJoe Beteta skreq->pbuf = NULL; 2481f52228b8SJoe Beteta skreq->state = SKD_REQ_STATE_IDLE; 2482f52228b8SJoe Beteta skreq->id += SKD_ID_INCR; 2483f52228b8SJoe Beteta } 2484f52228b8SJoe Beteta if (i > 0) { 2485f52228b8SJoe Beteta skreq[-1].next = skreq; 2486f52228b8SJoe Beteta } 2487f52228b8SJoe Beteta skreq->next = NULL; 2488f52228b8SJoe Beteta } 2489f52228b8SJoe Beteta 2490f52228b8SJoe Beteta WAITQ_LOCK(skdev); 2491f52228b8SJoe Beteta skdev->skreq_free_list = skdev->skreq_table; 2492f52228b8SJoe Beteta WAITQ_UNLOCK(skdev); 2493f52228b8SJoe Beteta 2494f52228b8SJoe Beteta for (i = 0; i < skdev->num_fitmsg_context; i++) { 2495f52228b8SJoe Beteta struct skd_fitmsg_context *skmsg = &skdev->skmsg_table[i]; 2496f52228b8SJoe Beteta 2497f52228b8SJoe Beteta if (skmsg->state == SKD_MSG_STATE_BUSY) { 2498f52228b8SJoe Beteta skd_log_skmsg(skdev, skmsg, "salvaged"); 2499f52228b8SJoe Beteta ASSERT((skmsg->id & SKD_ID_INCR) != 0); 2500f52228b8SJoe Beteta skmsg->state = SKD_MSG_STATE_IDLE; 2501f52228b8SJoe Beteta skmsg->id &= ~SKD_ID_INCR; 2502f52228b8SJoe Beteta } 2503f52228b8SJoe Beteta if (i > 0) { 2504f52228b8SJoe Beteta skmsg[-1].next = skmsg; 2505f52228b8SJoe Beteta } 2506f52228b8SJoe Beteta skmsg->next = NULL; 2507f52228b8SJoe Beteta } 2508f52228b8SJoe Beteta WAITQ_LOCK(skdev); 2509f52228b8SJoe Beteta skdev->skmsg_free_list = skdev->skmsg_table; 2510f52228b8SJoe Beteta WAITQ_UNLOCK(skdev); 2511f52228b8SJoe Beteta 2512f52228b8SJoe Beteta for (i = 0; i < SKD_N_TIMEOUT_SLOT; i++) { 2513f52228b8SJoe Beteta skdev->timeout_slot[i] = 0; 2514f52228b8SJoe Beteta } 2515f52228b8SJoe Beteta skdev->queue_depth_busy = 0; 2516f52228b8SJoe Beteta } 2517f52228b8SJoe Beteta 2518f52228b8SJoe Beteta /* 2519f52228b8SJoe Beteta * 2520f52228b8SJoe Beteta * Name: skd_isr_msg_from_dev, handles a message from the device. 2521f52228b8SJoe Beteta * 2522f52228b8SJoe Beteta * Inputs: skdev - device state structure. 2523f52228b8SJoe Beteta * 2524f52228b8SJoe Beteta * Returns: Nothing. 2525f52228b8SJoe Beteta * 2526f52228b8SJoe Beteta */ 2527f52228b8SJoe Beteta static void 2528f52228b8SJoe Beteta skd_isr_msg_from_dev(struct skd_device *skdev) 2529f52228b8SJoe Beteta { 2530f52228b8SJoe Beteta uint32_t mfd; 2531f52228b8SJoe Beteta uint32_t mtd; 2532f52228b8SJoe Beteta 2533f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "skd_isr_msg_from_dev:"); 2534f52228b8SJoe Beteta 2535f52228b8SJoe Beteta mfd = SKD_READL(skdev, FIT_MSG_FROM_DEVICE); 2536f52228b8SJoe Beteta 2537f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "mfd=0x%x last_mtd=0x%x\n", mfd, skdev->last_mtd); 2538f52228b8SJoe Beteta 2539f52228b8SJoe Beteta /* 2540f52228b8SJoe Beteta * ignore any mtd that is an ack for something we didn't send 2541f52228b8SJoe Beteta */ 2542f52228b8SJoe Beteta if (FIT_MXD_TYPE(mfd) != FIT_MXD_TYPE(skdev->last_mtd)) { 2543f52228b8SJoe Beteta return; 2544f52228b8SJoe Beteta } 2545f52228b8SJoe Beteta 2546f52228b8SJoe Beteta switch (FIT_MXD_TYPE(mfd)) { 2547f52228b8SJoe Beteta case FIT_MTD_FITFW_INIT: 2548f52228b8SJoe Beteta skdev->proto_ver = FIT_PROTOCOL_MAJOR_VER(mfd); 2549f52228b8SJoe Beteta 2550f52228b8SJoe Beteta if (skdev->proto_ver != FIT_PROTOCOL_VERSION_1) { 2551f52228b8SJoe Beteta cmn_err(CE_WARN, "!(%s): protocol mismatch\n", 2552f52228b8SJoe Beteta skdev->name); 2553f52228b8SJoe Beteta cmn_err(CE_WARN, "!(%s): got=%d support=%d\n", 2554f52228b8SJoe Beteta skdev->name, skdev->proto_ver, 2555f52228b8SJoe Beteta FIT_PROTOCOL_VERSION_1); 2556f52228b8SJoe Beteta cmn_err(CE_WARN, "!(%s): please upgrade driver\n", 2557f52228b8SJoe Beteta skdev->name); 2558f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_PROTOCOL_MISMATCH; 2559f52228b8SJoe Beteta skd_soft_reset(skdev); 2560f52228b8SJoe Beteta break; 2561f52228b8SJoe Beteta } 2562f52228b8SJoe Beteta mtd = FIT_MXD_CONS(FIT_MTD_GET_CMDQ_DEPTH, 0, 0); 2563f52228b8SJoe Beteta SKD_WRITEL(skdev, mtd, FIT_MSG_TO_DEVICE); 2564f52228b8SJoe Beteta skdev->last_mtd = mtd; 2565f52228b8SJoe Beteta break; 2566f52228b8SJoe Beteta 2567f52228b8SJoe Beteta case FIT_MTD_GET_CMDQ_DEPTH: 2568f52228b8SJoe Beteta skdev->hard_queue_depth_limit = FIT_MXD_DATA(mfd); 2569f52228b8SJoe Beteta mtd = FIT_MXD_CONS(FIT_MTD_SET_COMPQ_DEPTH, 0, 2570f52228b8SJoe Beteta SKD_N_COMPLETION_ENTRY); 2571f52228b8SJoe Beteta SKD_WRITEL(skdev, mtd, FIT_MSG_TO_DEVICE); 2572f52228b8SJoe Beteta skdev->last_mtd = mtd; 2573f52228b8SJoe Beteta break; 2574f52228b8SJoe Beteta 2575f52228b8SJoe Beteta case FIT_MTD_SET_COMPQ_DEPTH: 2576f52228b8SJoe Beteta SKD_WRITEQ(skdev, skdev->cq_dma_address.cookies->dmac_laddress, 2577f52228b8SJoe Beteta FIT_MSG_TO_DEVICE_ARG); 2578f52228b8SJoe Beteta mtd = FIT_MXD_CONS(FIT_MTD_SET_COMPQ_ADDR, 0, 0); 2579f52228b8SJoe Beteta SKD_WRITEL(skdev, mtd, FIT_MSG_TO_DEVICE); 2580f52228b8SJoe Beteta skdev->last_mtd = mtd; 2581f52228b8SJoe Beteta break; 2582f52228b8SJoe Beteta 2583f52228b8SJoe Beteta case FIT_MTD_SET_COMPQ_ADDR: 2584f52228b8SJoe Beteta skd_reset_skcomp(skdev); 2585f52228b8SJoe Beteta mtd = FIT_MXD_CONS(FIT_MTD_ARM_QUEUE, 0, 0); 2586f52228b8SJoe Beteta SKD_WRITEL(skdev, mtd, FIT_MSG_TO_DEVICE); 2587f52228b8SJoe Beteta skdev->last_mtd = mtd; 2588f52228b8SJoe Beteta break; 2589f52228b8SJoe Beteta 2590f52228b8SJoe Beteta case FIT_MTD_ARM_QUEUE: 2591f52228b8SJoe Beteta skdev->last_mtd = 0; 2592f52228b8SJoe Beteta /* 2593f52228b8SJoe Beteta * State should be, or soon will be, FIT_SR_DRIVE_ONLINE. 2594f52228b8SJoe Beteta */ 2595f52228b8SJoe Beteta break; 2596f52228b8SJoe Beteta 2597f52228b8SJoe Beteta default: 2598f52228b8SJoe Beteta break; 2599f52228b8SJoe Beteta } 2600f52228b8SJoe Beteta } 2601f52228b8SJoe Beteta 2602f52228b8SJoe Beteta 2603f52228b8SJoe Beteta /* 2604f52228b8SJoe Beteta * 2605f52228b8SJoe Beteta * Name: skd_disable_interrupts, issues command to disable 2606f52228b8SJoe Beteta * device interrupts. 2607f52228b8SJoe Beteta * 2608f52228b8SJoe Beteta * Inputs: skdev - device state structure. 2609f52228b8SJoe Beteta * 2610f52228b8SJoe Beteta * Returns: Nothing. 2611f52228b8SJoe Beteta * 2612f52228b8SJoe Beteta */ 2613f52228b8SJoe Beteta static void 2614f52228b8SJoe Beteta skd_disable_interrupts(struct skd_device *skdev) 2615f52228b8SJoe Beteta { 2616f52228b8SJoe Beteta uint32_t sense; 2617f52228b8SJoe Beteta 2618f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "skd_disable_interrupts:"); 2619f52228b8SJoe Beteta 2620f52228b8SJoe Beteta sense = SKD_READL(skdev, FIT_CONTROL); 2621f52228b8SJoe Beteta sense &= ~FIT_CR_ENABLE_INTERRUPTS; 2622f52228b8SJoe Beteta SKD_WRITEL(skdev, sense, FIT_CONTROL); 2623f52228b8SJoe Beteta 2624f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "sense 0x%x", sense); 2625f52228b8SJoe Beteta 2626f52228b8SJoe Beteta /* 2627f52228b8SJoe Beteta * Note that the 1s is written. A 1-bit means 2628f52228b8SJoe Beteta * disable, a 0 means enable. 2629f52228b8SJoe Beteta */ 2630f52228b8SJoe Beteta SKD_WRITEL(skdev, ~0, FIT_INT_MASK_HOST); 2631f52228b8SJoe Beteta } 2632f52228b8SJoe Beteta 2633f52228b8SJoe Beteta /* 2634f52228b8SJoe Beteta * 2635f52228b8SJoe Beteta * Name: skd_enable_interrupts, issues command to enable 2636f52228b8SJoe Beteta * device interrupts. 2637f52228b8SJoe Beteta * 2638f52228b8SJoe Beteta * Inputs: skdev - device state structure. 2639f52228b8SJoe Beteta * 2640f52228b8SJoe Beteta * Returns: Nothing. 2641f52228b8SJoe Beteta * 2642f52228b8SJoe Beteta */ 2643f52228b8SJoe Beteta static void 2644f52228b8SJoe Beteta skd_enable_interrupts(struct skd_device *skdev) 2645f52228b8SJoe Beteta { 2646f52228b8SJoe Beteta uint32_t val; 2647f52228b8SJoe Beteta 2648f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "skd_enable_interrupts:"); 2649f52228b8SJoe Beteta 2650f52228b8SJoe Beteta /* unmask interrupts first */ 2651f52228b8SJoe Beteta val = FIT_ISH_FW_STATE_CHANGE + 2652f52228b8SJoe Beteta FIT_ISH_COMPLETION_POSTED + 2653f52228b8SJoe Beteta FIT_ISH_MSG_FROM_DEV; 2654f52228b8SJoe Beteta 2655f52228b8SJoe Beteta /* 2656f52228b8SJoe Beteta * Note that the compliment of mask is written. A 1-bit means 2657f52228b8SJoe Beteta * disable, a 0 means enable. 2658f52228b8SJoe Beteta */ 2659f52228b8SJoe Beteta SKD_WRITEL(skdev, ~val, FIT_INT_MASK_HOST); 2660f52228b8SJoe Beteta 2661f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "interrupt mask=0x%x", ~val); 2662f52228b8SJoe Beteta 2663f52228b8SJoe Beteta val = SKD_READL(skdev, FIT_CONTROL); 2664f52228b8SJoe Beteta val |= FIT_CR_ENABLE_INTERRUPTS; 2665f52228b8SJoe Beteta 2666f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "control=0x%x", val); 2667f52228b8SJoe Beteta 2668f52228b8SJoe Beteta SKD_WRITEL(skdev, val, FIT_CONTROL); 2669f52228b8SJoe Beteta } 2670f52228b8SJoe Beteta 2671f52228b8SJoe Beteta /* 2672f52228b8SJoe Beteta * 2673f52228b8SJoe Beteta * Name: skd_soft_reset, issues a soft reset to the hardware. 2674f52228b8SJoe Beteta * 2675f52228b8SJoe Beteta * Inputs: skdev - device state structure. 2676f52228b8SJoe Beteta * 2677f52228b8SJoe Beteta * Returns: Nothing. 2678f52228b8SJoe Beteta * 2679f52228b8SJoe Beteta */ 2680f52228b8SJoe Beteta static void 2681f52228b8SJoe Beteta skd_soft_reset(struct skd_device *skdev) 2682f52228b8SJoe Beteta { 2683f52228b8SJoe Beteta uint32_t val; 2684f52228b8SJoe Beteta 2685f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "skd_soft_reset:"); 2686f52228b8SJoe Beteta 2687f52228b8SJoe Beteta val = SKD_READL(skdev, FIT_CONTROL); 2688f52228b8SJoe Beteta val |= (FIT_CR_SOFT_RESET); 2689f52228b8SJoe Beteta 2690f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "soft_reset: control=0x%x", val); 2691f52228b8SJoe Beteta 2692f52228b8SJoe Beteta SKD_WRITEL(skdev, val, FIT_CONTROL); 2693f52228b8SJoe Beteta } 2694f52228b8SJoe Beteta 2695f52228b8SJoe Beteta /* 2696f52228b8SJoe Beteta * 2697f52228b8SJoe Beteta * Name: skd_start_device, gets the device going. 2698f52228b8SJoe Beteta * 2699f52228b8SJoe Beteta * Inputs: skdev - device state structure. 2700f52228b8SJoe Beteta * 2701f52228b8SJoe Beteta * Returns: Nothing. 2702f52228b8SJoe Beteta * 2703f52228b8SJoe Beteta */ 2704f52228b8SJoe Beteta static void 2705f52228b8SJoe Beteta skd_start_device(struct skd_device *skdev) 2706f52228b8SJoe Beteta { 2707f52228b8SJoe Beteta uint32_t state; 2708f52228b8SJoe Beteta int delay_action = 0; 2709f52228b8SJoe Beteta 2710f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "skd_start_device:"); 2711f52228b8SJoe Beteta 2712f52228b8SJoe Beteta /* ack all ghost interrupts */ 2713f52228b8SJoe Beteta SKD_WRITEL(skdev, FIT_INT_DEF_MASK, FIT_INT_STATUS_HOST); 2714f52228b8SJoe Beteta 2715f52228b8SJoe Beteta state = SKD_READL(skdev, FIT_STATUS); 2716f52228b8SJoe Beteta 2717f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "initial status=0x%x", state); 2718f52228b8SJoe Beteta 2719f52228b8SJoe Beteta state &= FIT_SR_DRIVE_STATE_MASK; 2720f52228b8SJoe Beteta skdev->drive_state = state; 2721f52228b8SJoe Beteta skdev->last_mtd = 0; 2722f52228b8SJoe Beteta 2723f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_STARTING; 2724f52228b8SJoe Beteta skdev->timer_countdown = SKD_TIMER_SECONDS(SKD_STARTING_TO); 2725f52228b8SJoe Beteta 2726f52228b8SJoe Beteta skd_enable_interrupts(skdev); 2727f52228b8SJoe Beteta 2728f52228b8SJoe Beteta switch (skdev->drive_state) { 2729f52228b8SJoe Beteta case FIT_SR_DRIVE_OFFLINE: 2730f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "(%s): Drive offline...", 2731f52228b8SJoe Beteta skd_name(skdev)); 2732f52228b8SJoe Beteta break; 2733f52228b8SJoe Beteta 2734f52228b8SJoe Beteta case FIT_SR_DRIVE_FW_BOOTING: 2735f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "FIT_SR_DRIVE_FW_BOOTING %s\n", skdev->name); 2736f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_WAIT_BOOT; 2737f52228b8SJoe Beteta skdev->timer_countdown = SKD_TIMER_SECONDS(SKD_WAIT_BOOT_TO); 2738f52228b8SJoe Beteta break; 2739f52228b8SJoe Beteta 2740f52228b8SJoe Beteta case FIT_SR_DRIVE_BUSY_SANITIZE: 2741f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "(%s): Start: BUSY_SANITIZE\n", 2742f52228b8SJoe Beteta skd_name(skdev)); 2743f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_BUSY_SANITIZE; 2744f52228b8SJoe Beteta skdev->timer_countdown = SKD_TIMER_SECONDS(60); 2745f52228b8SJoe Beteta break; 2746f52228b8SJoe Beteta 2747f52228b8SJoe Beteta case FIT_SR_DRIVE_BUSY_ERASE: 2748f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "(%s): Start: BUSY_ERASE\n", 2749f52228b8SJoe Beteta skd_name(skdev)); 2750f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_BUSY_ERASE; 2751f52228b8SJoe Beteta skdev->timer_countdown = SKD_TIMER_SECONDS(60); 2752f52228b8SJoe Beteta break; 2753f52228b8SJoe Beteta 2754f52228b8SJoe Beteta case FIT_SR_DRIVE_INIT: 2755f52228b8SJoe Beteta case FIT_SR_DRIVE_ONLINE: 2756f52228b8SJoe Beteta skd_soft_reset(skdev); 2757f52228b8SJoe Beteta 2758f52228b8SJoe Beteta break; 2759f52228b8SJoe Beteta 2760f52228b8SJoe Beteta case FIT_SR_DRIVE_BUSY: 2761f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "(%s): Drive Busy...\n", 2762f52228b8SJoe Beteta skd_name(skdev)); 2763f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_BUSY; 2764f52228b8SJoe Beteta skdev->timer_countdown = SKD_TIMER_SECONDS(60); 2765f52228b8SJoe Beteta break; 2766f52228b8SJoe Beteta 2767f52228b8SJoe Beteta case FIT_SR_DRIVE_SOFT_RESET: 2768f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "(%s) drive soft reset in prog\n", 2769f52228b8SJoe Beteta skd_name(skdev)); 2770f52228b8SJoe Beteta break; 2771f52228b8SJoe Beteta 2772f52228b8SJoe Beteta case FIT_SR_DRIVE_FAULT: 2773f52228b8SJoe Beteta /* 2774f52228b8SJoe Beteta * Fault state is bad...soft reset won't do it... 2775f52228b8SJoe Beteta * Hard reset, maybe, but does it work on device? 2776f52228b8SJoe Beteta * For now, just fault so the system doesn't hang. 2777f52228b8SJoe Beteta */ 2778f52228b8SJoe Beteta skd_drive_fault(skdev); 2779f52228b8SJoe Beteta 2780f52228b8SJoe Beteta delay_action = 1; 2781f52228b8SJoe Beteta break; 2782f52228b8SJoe Beteta 2783f52228b8SJoe Beteta case 0xFF: 2784f52228b8SJoe Beteta skd_drive_disappeared(skdev); 2785f52228b8SJoe Beteta 2786f52228b8SJoe Beteta delay_action = 1; 2787f52228b8SJoe Beteta break; 2788f52228b8SJoe Beteta 2789f52228b8SJoe Beteta default: 2790f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "(%s) Start: unknown state %x\n", 2791f52228b8SJoe Beteta skd_name(skdev), skdev->drive_state); 2792f52228b8SJoe Beteta break; 2793f52228b8SJoe Beteta } 2794f52228b8SJoe Beteta 2795f52228b8SJoe Beteta state = SKD_READL(skdev, FIT_CONTROL); 2796f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "FIT Control Status=0x%x\n", state); 2797f52228b8SJoe Beteta 2798f52228b8SJoe Beteta state = SKD_READL(skdev, FIT_INT_STATUS_HOST); 2799f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "Intr Status=0x%x\n", state); 2800f52228b8SJoe Beteta 2801f52228b8SJoe Beteta state = SKD_READL(skdev, FIT_INT_MASK_HOST); 2802f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "Intr Mask=0x%x\n", state); 2803f52228b8SJoe Beteta 2804f52228b8SJoe Beteta state = SKD_READL(skdev, FIT_MSG_FROM_DEVICE); 2805f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "Msg from Dev=0x%x\n", state); 2806f52228b8SJoe Beteta 2807f52228b8SJoe Beteta state = SKD_READL(skdev, FIT_HW_VERSION); 2808f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "HW version=0x%x\n", state); 2809f52228b8SJoe Beteta 2810f52228b8SJoe Beteta if (delay_action) { 2811f52228b8SJoe Beteta /* start the queue so we can respond with error to requests */ 2812f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "Starting %s queue\n", skdev->name); 2813f52228b8SJoe Beteta skd_start(skdev); 2814f52228b8SJoe Beteta skdev->gendisk_on = -1; 2815f52228b8SJoe Beteta cv_signal(&skdev->cv_waitq); 2816f52228b8SJoe Beteta } 2817f52228b8SJoe Beteta } 2818f52228b8SJoe Beteta 2819f52228b8SJoe Beteta /* 2820f52228b8SJoe Beteta * 2821f52228b8SJoe Beteta * Name: skd_restart_device, restart the hardware. 2822f52228b8SJoe Beteta * 2823f52228b8SJoe Beteta * Inputs: skdev - device state structure. 2824f52228b8SJoe Beteta * 2825f52228b8SJoe Beteta * Returns: Nothing. 2826f52228b8SJoe Beteta * 2827f52228b8SJoe Beteta */ 2828f52228b8SJoe Beteta static void 2829f52228b8SJoe Beteta skd_restart_device(struct skd_device *skdev) 2830f52228b8SJoe Beteta { 2831f52228b8SJoe Beteta uint32_t state; 2832f52228b8SJoe Beteta 2833f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "skd_restart_device:"); 2834f52228b8SJoe Beteta 2835f52228b8SJoe Beteta /* ack all ghost interrupts */ 2836f52228b8SJoe Beteta SKD_WRITEL(skdev, FIT_INT_DEF_MASK, FIT_INT_STATUS_HOST); 2837f52228b8SJoe Beteta 2838f52228b8SJoe Beteta state = SKD_READL(skdev, FIT_STATUS); 2839f52228b8SJoe Beteta 2840f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "skd_restart_device: drive status=0x%x\n", state); 2841f52228b8SJoe Beteta 2842f52228b8SJoe Beteta state &= FIT_SR_DRIVE_STATE_MASK; 2843f52228b8SJoe Beteta skdev->drive_state = state; 2844f52228b8SJoe Beteta skdev->last_mtd = 0; 2845f52228b8SJoe Beteta 2846f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_RESTARTING; 2847f52228b8SJoe Beteta skdev->timer_countdown = SKD_TIMER_MINUTES(4); 2848f52228b8SJoe Beteta 2849f52228b8SJoe Beteta skd_soft_reset(skdev); 2850f52228b8SJoe Beteta } 2851f52228b8SJoe Beteta 2852f52228b8SJoe Beteta /* 2853f52228b8SJoe Beteta * 2854f52228b8SJoe Beteta * Name: skd_stop_device, stops the device. 2855f52228b8SJoe Beteta * 2856f52228b8SJoe Beteta * Inputs: skdev - device state structure. 2857f52228b8SJoe Beteta * 2858f52228b8SJoe Beteta * Returns: Nothing. 2859f52228b8SJoe Beteta * 2860f52228b8SJoe Beteta */ 2861f52228b8SJoe Beteta static void 2862f52228b8SJoe Beteta skd_stop_device(struct skd_device *skdev) 2863f52228b8SJoe Beteta { 2864f52228b8SJoe Beteta clock_t cur_ticks, tmo; 2865f52228b8SJoe Beteta int secs; 2866f52228b8SJoe Beteta struct skd_special_context *skspcl = &skdev->internal_skspcl; 2867f52228b8SJoe Beteta 2868f52228b8SJoe Beteta if (SKD_DRVR_STATE_ONLINE != skdev->state) { 2869f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "(%s): skd_stop_device not online no sync\n", 2870f52228b8SJoe Beteta skdev->name); 2871f52228b8SJoe Beteta goto stop_out; 2872f52228b8SJoe Beteta } 2873f52228b8SJoe Beteta 2874f52228b8SJoe Beteta if (SKD_REQ_STATE_IDLE != skspcl->req.state) { 2875f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "(%s): skd_stop_device no special\n", 2876f52228b8SJoe Beteta skdev->name); 2877f52228b8SJoe Beteta goto stop_out; 2878f52228b8SJoe Beteta } 2879f52228b8SJoe Beteta 2880f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_SYNCING; 2881f52228b8SJoe Beteta skdev->sync_done = 0; 2882f52228b8SJoe Beteta 2883f52228b8SJoe Beteta skd_send_internal_skspcl(skdev, skspcl, SYNCHRONIZE_CACHE); 2884f52228b8SJoe Beteta 2885f52228b8SJoe Beteta secs = 10; 2886f52228b8SJoe Beteta mutex_enter(&skdev->skd_internalio_mutex); 2887f52228b8SJoe Beteta while (skdev->sync_done == 0) { 2888f52228b8SJoe Beteta cur_ticks = ddi_get_lbolt(); 2889f52228b8SJoe Beteta tmo = cur_ticks + drv_usectohz(1000000 * secs); 2890f52228b8SJoe Beteta if (cv_timedwait(&skdev->cv_waitq, 2891f52228b8SJoe Beteta &skdev->skd_internalio_mutex, tmo) == -1) { 2892f52228b8SJoe Beteta /* Oops - timed out */ 2893f52228b8SJoe Beteta 2894f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "stop_device - %d secs TMO", secs); 2895f52228b8SJoe Beteta } 2896f52228b8SJoe Beteta } 2897f52228b8SJoe Beteta 2898f52228b8SJoe Beteta mutex_exit(&skdev->skd_internalio_mutex); 2899f52228b8SJoe Beteta 2900f52228b8SJoe Beteta switch (skdev->sync_done) { 2901f52228b8SJoe Beteta case 0: 2902f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "(%s): skd_stop_device no sync\n", 2903f52228b8SJoe Beteta skdev->name); 2904f52228b8SJoe Beteta break; 2905f52228b8SJoe Beteta case 1: 2906f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "(%s): skd_stop_device sync done\n", 2907f52228b8SJoe Beteta skdev->name); 2908f52228b8SJoe Beteta break; 2909f52228b8SJoe Beteta default: 2910f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "(%s): skd_stop_device sync error\n", 2911f52228b8SJoe Beteta skdev->name); 2912f52228b8SJoe Beteta } 2913f52228b8SJoe Beteta 2914f52228b8SJoe Beteta 2915f52228b8SJoe Beteta stop_out: 2916f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_STOPPING; 2917f52228b8SJoe Beteta 2918f52228b8SJoe Beteta skd_disable_interrupts(skdev); 2919f52228b8SJoe Beteta 2920f52228b8SJoe Beteta /* ensure all ints on device are cleared */ 2921f52228b8SJoe Beteta SKD_WRITEL(skdev, FIT_INT_DEF_MASK, FIT_INT_STATUS_HOST); 2922f52228b8SJoe Beteta /* soft reset the device to unload with a clean slate */ 2923f52228b8SJoe Beteta SKD_WRITEL(skdev, FIT_CR_SOFT_RESET, FIT_CONTROL); 2924f52228b8SJoe Beteta } 2925f52228b8SJoe Beteta 2926f52228b8SJoe Beteta /* 2927f52228b8SJoe Beteta * CONSTRUCT 2928f52228b8SJoe Beteta */ 2929f52228b8SJoe Beteta 2930f52228b8SJoe Beteta static int skd_cons_skcomp(struct skd_device *); 2931f52228b8SJoe Beteta static int skd_cons_skmsg(struct skd_device *); 2932f52228b8SJoe Beteta static int skd_cons_skreq(struct skd_device *); 2933f52228b8SJoe Beteta static int skd_cons_sksb(struct skd_device *); 2934f52228b8SJoe Beteta static struct fit_sg_descriptor *skd_cons_sg_list(struct skd_device *, uint32_t, 2935f52228b8SJoe Beteta dma_mem_t *); 2936f52228b8SJoe Beteta 2937f52228b8SJoe Beteta /* 2938f52228b8SJoe Beteta * 2939f52228b8SJoe Beteta * Name: skd_construct, calls other routines to build device 2940f52228b8SJoe Beteta * interface structures. 2941f52228b8SJoe Beteta * 2942f52228b8SJoe Beteta * Inputs: skdev - device state structure. 2943f52228b8SJoe Beteta * instance - DDI instance number. 2944f52228b8SJoe Beteta * 2945f52228b8SJoe Beteta * Returns: Returns DDI_FAILURE on any failure otherwise returns 2946f52228b8SJoe Beteta * DDI_SUCCESS. 2947f52228b8SJoe Beteta * 2948f52228b8SJoe Beteta */ 2949f52228b8SJoe Beteta /* ARGSUSED */ /* Upstream common source with other platforms. */ 2950f52228b8SJoe Beteta static int 2951f52228b8SJoe Beteta skd_construct(skd_device_t *skdev, int instance) 2952f52228b8SJoe Beteta { 2953f52228b8SJoe Beteta int rc = 0; 2954f52228b8SJoe Beteta 2955f52228b8SJoe Beteta skdev->state = SKD_DRVR_STATE_LOAD; 2956f52228b8SJoe Beteta skdev->irq_type = skd_isr_type; 2957f52228b8SJoe Beteta skdev->soft_queue_depth_limit = skd_max_queue_depth; 2958f52228b8SJoe Beteta skdev->hard_queue_depth_limit = 10; /* until GET_CMDQ_DEPTH */ 2959f52228b8SJoe Beteta 2960f52228b8SJoe Beteta skdev->num_req_context = skd_max_queue_depth; 2961f52228b8SJoe Beteta skdev->num_fitmsg_context = skd_max_queue_depth; 2962f52228b8SJoe Beteta 2963f52228b8SJoe Beteta skdev->queue_depth_limit = skdev->hard_queue_depth_limit; 2964f52228b8SJoe Beteta skdev->queue_depth_lowat = 1; 2965f52228b8SJoe Beteta skdev->proto_ver = 99; /* initialize to invalid value */ 2966f52228b8SJoe Beteta skdev->sgs_per_request = skd_sgs_per_request; 2967f52228b8SJoe Beteta skdev->dbg_level = skd_dbg_level; 2968f52228b8SJoe Beteta 2969f52228b8SJoe Beteta rc = skd_cons_skcomp(skdev); 2970f52228b8SJoe Beteta if (rc < 0) { 2971f52228b8SJoe Beteta goto err_out; 2972f52228b8SJoe Beteta } 2973f52228b8SJoe Beteta 2974f52228b8SJoe Beteta rc = skd_cons_skmsg(skdev); 2975f52228b8SJoe Beteta if (rc < 0) { 2976f52228b8SJoe Beteta goto err_out; 2977f52228b8SJoe Beteta } 2978f52228b8SJoe Beteta 2979f52228b8SJoe Beteta rc = skd_cons_skreq(skdev); 2980f52228b8SJoe Beteta if (rc < 0) { 2981f52228b8SJoe Beteta goto err_out; 2982f52228b8SJoe Beteta } 2983f52228b8SJoe Beteta 2984f52228b8SJoe Beteta rc = skd_cons_sksb(skdev); 2985f52228b8SJoe Beteta if (rc < 0) { 2986f52228b8SJoe Beteta goto err_out; 2987f52228b8SJoe Beteta } 2988f52228b8SJoe Beteta 2989f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "CONSTRUCT VICTORY"); 2990f52228b8SJoe Beteta 2991f52228b8SJoe Beteta return (DDI_SUCCESS); 2992f52228b8SJoe Beteta 2993f52228b8SJoe Beteta err_out: 2994f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "construct failed\n"); 2995f52228b8SJoe Beteta skd_destruct(skdev); 2996f52228b8SJoe Beteta 2997f52228b8SJoe Beteta return (DDI_FAILURE); 2998f52228b8SJoe Beteta } 2999f52228b8SJoe Beteta 3000f52228b8SJoe Beteta /* 3001f52228b8SJoe Beteta * 3002f52228b8SJoe Beteta * Name: skd_free_phys, frees DMA memory. 3003f52228b8SJoe Beteta * 3004f52228b8SJoe Beteta * Inputs: skdev - device state structure. 3005f52228b8SJoe Beteta * mem - DMA info. 3006f52228b8SJoe Beteta * 3007f52228b8SJoe Beteta * Returns: Nothing. 3008f52228b8SJoe Beteta * 3009f52228b8SJoe Beteta */ 3010f52228b8SJoe Beteta static void 3011f52228b8SJoe Beteta skd_free_phys(skd_device_t *skdev, dma_mem_t *mem) 3012f52228b8SJoe Beteta { 3013f52228b8SJoe Beteta _NOTE(ARGUNUSED(skdev)); 3014f52228b8SJoe Beteta 3015f52228b8SJoe Beteta if (mem == NULL || mem->dma_handle == NULL) 3016f52228b8SJoe Beteta return; 3017f52228b8SJoe Beteta 3018f52228b8SJoe Beteta (void) ddi_dma_unbind_handle(mem->dma_handle); 3019f52228b8SJoe Beteta 3020f52228b8SJoe Beteta if (mem->acc_handle != NULL) { 3021f52228b8SJoe Beteta ddi_dma_mem_free(&mem->acc_handle); 3022f52228b8SJoe Beteta mem->acc_handle = NULL; 3023f52228b8SJoe Beteta } 3024f52228b8SJoe Beteta 3025f52228b8SJoe Beteta mem->bp = NULL; 3026f52228b8SJoe Beteta ddi_dma_free_handle(&mem->dma_handle); 3027f52228b8SJoe Beteta mem->dma_handle = NULL; 3028f52228b8SJoe Beteta } 3029f52228b8SJoe Beteta 3030f52228b8SJoe Beteta /* 3031f52228b8SJoe Beteta * 3032f52228b8SJoe Beteta * Name: skd_alloc_dma_mem, allocates DMA memory. 3033f52228b8SJoe Beteta * 3034f52228b8SJoe Beteta * Inputs: skdev - device state structure. 3035f52228b8SJoe Beteta * mem - DMA data structure. 3036f52228b8SJoe Beteta * sleep - indicates whether called routine can sleep. 3037f52228b8SJoe Beteta * atype - specified 32 or 64 bit allocation. 3038f52228b8SJoe Beteta * 3039f52228b8SJoe Beteta * Returns: Void pointer to mem->bp on success else NULL. 3040f52228b8SJoe Beteta * NOTE: There are some failure modes even if sleep is set 3041f52228b8SJoe Beteta * to KM_SLEEP, so callers MUST check the return code even 3042f52228b8SJoe Beteta * if KM_SLEEP is passed in. 3043f52228b8SJoe Beteta * 3044f52228b8SJoe Beteta */ 3045f52228b8SJoe Beteta static void * 3046f52228b8SJoe Beteta skd_alloc_dma_mem(skd_device_t *skdev, dma_mem_t *mem, uint8_t atype) 3047f52228b8SJoe Beteta { 3048f52228b8SJoe Beteta size_t rlen; 3049f52228b8SJoe Beteta uint_t cnt; 3050f52228b8SJoe Beteta ddi_dma_attr_t dma_attr = skd_64bit_io_dma_attr; 3051f52228b8SJoe Beteta ddi_device_acc_attr_t acc_attr = { 3052f52228b8SJoe Beteta DDI_DEVICE_ATTR_V0, 3053f52228b8SJoe Beteta DDI_STRUCTURE_LE_ACC, 3054f52228b8SJoe Beteta DDI_STRICTORDER_ACC 3055f52228b8SJoe Beteta }; 3056f52228b8SJoe Beteta 3057f52228b8SJoe Beteta if (atype == ATYPE_32BIT) 3058f52228b8SJoe Beteta dma_attr.dma_attr_addr_hi = SKD_DMA_HIGH_32BIT_ADDRESS; 3059f52228b8SJoe Beteta 3060f52228b8SJoe Beteta dma_attr.dma_attr_sgllen = 1; 3061f52228b8SJoe Beteta 3062f52228b8SJoe Beteta /* 3063f52228b8SJoe Beteta * Allocate DMA memory. 3064f52228b8SJoe Beteta */ 3065f52228b8SJoe Beteta if (ddi_dma_alloc_handle(skdev->dip, &dma_attr, DDI_DMA_SLEEP, NULL, 3066f52228b8SJoe Beteta &mem->dma_handle) != DDI_SUCCESS) { 3067f52228b8SJoe Beteta cmn_err(CE_WARN, "!alloc_dma_mem-1, failed"); 3068f52228b8SJoe Beteta 3069f52228b8SJoe Beteta mem->dma_handle = NULL; 3070f52228b8SJoe Beteta 3071f52228b8SJoe Beteta return (NULL); 3072f52228b8SJoe Beteta } 3073f52228b8SJoe Beteta 3074f52228b8SJoe Beteta if (ddi_dma_mem_alloc(mem->dma_handle, mem->size, &acc_attr, 3075f52228b8SJoe Beteta DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, (caddr_t *)&mem->bp, &rlen, 3076f52228b8SJoe Beteta &mem->acc_handle) != DDI_SUCCESS) { 3077f52228b8SJoe Beteta cmn_err(CE_WARN, "!skd_alloc_dma_mem-2, failed"); 3078f52228b8SJoe Beteta ddi_dma_free_handle(&mem->dma_handle); 3079f52228b8SJoe Beteta mem->dma_handle = NULL; 3080f52228b8SJoe Beteta mem->acc_handle = NULL; 3081f52228b8SJoe Beteta mem->bp = NULL; 3082f52228b8SJoe Beteta 3083f52228b8SJoe Beteta return (NULL); 3084f52228b8SJoe Beteta } 3085f52228b8SJoe Beteta bzero(mem->bp, mem->size); 3086f52228b8SJoe Beteta 3087f52228b8SJoe Beteta if (ddi_dma_addr_bind_handle(mem->dma_handle, NULL, mem->bp, 3088f52228b8SJoe Beteta mem->size, (DDI_DMA_CONSISTENT | DDI_DMA_RDWR), DDI_DMA_SLEEP, NULL, 3089f52228b8SJoe Beteta &mem->cookie, &cnt) != DDI_DMA_MAPPED) { 3090f52228b8SJoe Beteta cmn_err(CE_WARN, "!skd_alloc_dma_mem-3, failed"); 3091f52228b8SJoe Beteta ddi_dma_mem_free(&mem->acc_handle); 3092f52228b8SJoe Beteta ddi_dma_free_handle(&mem->dma_handle); 3093f52228b8SJoe Beteta 3094f52228b8SJoe Beteta return (NULL); 3095f52228b8SJoe Beteta } 3096f52228b8SJoe Beteta 3097f52228b8SJoe Beteta if (cnt > 1) { 3098f52228b8SJoe Beteta (void) ddi_dma_unbind_handle(mem->dma_handle); 3099f52228b8SJoe Beteta cmn_err(CE_WARN, "!skd_alloc_dma_mem-4, failed, " 3100f52228b8SJoe Beteta "cookie_count %d > 1", cnt); 3101f52228b8SJoe Beteta skd_free_phys(skdev, mem); 3102f52228b8SJoe Beteta 3103f52228b8SJoe Beteta return (NULL); 3104f52228b8SJoe Beteta } 3105f52228b8SJoe Beteta mem->cookies = &mem->cookie; 3106f52228b8SJoe Beteta mem->cookies->dmac_size = mem->size; 3107f52228b8SJoe Beteta 3108f52228b8SJoe Beteta return (mem->bp); 3109f52228b8SJoe Beteta } 3110f52228b8SJoe Beteta 3111f52228b8SJoe Beteta /* 3112f52228b8SJoe Beteta * 3113f52228b8SJoe Beteta * Name: skd_cons_skcomp, allocates space for the skcomp table. 3114f52228b8SJoe Beteta * 3115f52228b8SJoe Beteta * Inputs: skdev - device state structure. 3116f52228b8SJoe Beteta * 3117f52228b8SJoe Beteta * Returns: -ENOMEM if no memory otherwise NULL. 3118f52228b8SJoe Beteta * 3119f52228b8SJoe Beteta */ 3120f52228b8SJoe Beteta static int 3121f52228b8SJoe Beteta skd_cons_skcomp(struct skd_device *skdev) 3122f52228b8SJoe Beteta { 3123f52228b8SJoe Beteta uint64_t *dma_alloc; 3124f52228b8SJoe Beteta struct fit_completion_entry_v1 *skcomp; 3125f52228b8SJoe Beteta int rc = 0; 3126f52228b8SJoe Beteta uint32_t nbytes; 3127f52228b8SJoe Beteta dma_mem_t *mem; 3128f52228b8SJoe Beteta 3129f52228b8SJoe Beteta nbytes = sizeof (*skcomp) * SKD_N_COMPLETION_ENTRY; 3130f52228b8SJoe Beteta nbytes += sizeof (struct fit_comp_error_info) * SKD_N_COMPLETION_ENTRY; 3131f52228b8SJoe Beteta 3132f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "cons_skcomp: nbytes=%d,entries=%d", nbytes, 3133f52228b8SJoe Beteta SKD_N_COMPLETION_ENTRY); 3134f52228b8SJoe Beteta 3135f52228b8SJoe Beteta mem = &skdev->cq_dma_address; 3136f52228b8SJoe Beteta mem->size = nbytes; 3137f52228b8SJoe Beteta 3138f52228b8SJoe Beteta dma_alloc = skd_alloc_dma_mem(skdev, mem, ATYPE_64BIT); 3139f52228b8SJoe Beteta skcomp = (struct fit_completion_entry_v1 *)dma_alloc; 3140f52228b8SJoe Beteta if (skcomp == NULL) { 3141f52228b8SJoe Beteta rc = -ENOMEM; 3142f52228b8SJoe Beteta goto err_out; 3143f52228b8SJoe Beteta } 3144f52228b8SJoe Beteta 3145f52228b8SJoe Beteta bzero(skcomp, nbytes); 3146f52228b8SJoe Beteta 3147f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "cons_skcomp: skcomp=%p nbytes=%d", 3148f52228b8SJoe Beteta (void *)skcomp, nbytes); 3149f52228b8SJoe Beteta 3150f52228b8SJoe Beteta skdev->skcomp_table = skcomp; 3151f52228b8SJoe Beteta skdev->skerr_table = (struct fit_comp_error_info *)(dma_alloc + 3152f52228b8SJoe Beteta (SKD_N_COMPLETION_ENTRY * sizeof (*skcomp) / sizeof (uint64_t))); 3153f52228b8SJoe Beteta 3154f52228b8SJoe Beteta err_out: 3155f52228b8SJoe Beteta return (rc); 3156f52228b8SJoe Beteta } 3157f52228b8SJoe Beteta 3158f52228b8SJoe Beteta /* 3159f52228b8SJoe Beteta * 3160f52228b8SJoe Beteta * Name: skd_cons_skmsg, allocates space for the skmsg table. 3161f52228b8SJoe Beteta * 3162f52228b8SJoe Beteta * Inputs: skdev - device state structure. 3163f52228b8SJoe Beteta * 3164f52228b8SJoe Beteta * Returns: -ENOMEM if no memory otherwise NULL. 3165f52228b8SJoe Beteta * 3166f52228b8SJoe Beteta */ 3167f52228b8SJoe Beteta static int 3168f52228b8SJoe Beteta skd_cons_skmsg(struct skd_device *skdev) 3169f52228b8SJoe Beteta { 3170f52228b8SJoe Beteta dma_mem_t *mem; 3171f52228b8SJoe Beteta int rc = 0; 3172f52228b8SJoe Beteta uint32_t i; 3173f52228b8SJoe Beteta 3174f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "skmsg_table kzalloc, struct %lu, count %u total %lu", 3175f52228b8SJoe Beteta (ulong_t)sizeof (struct skd_fitmsg_context), 3176f52228b8SJoe Beteta skdev->num_fitmsg_context, 3177f52228b8SJoe Beteta (ulong_t)(sizeof (struct skd_fitmsg_context) * 3178f52228b8SJoe Beteta skdev->num_fitmsg_context)); 3179f52228b8SJoe Beteta 3180f52228b8SJoe Beteta skdev->skmsg_table = (struct skd_fitmsg_context *)kmem_zalloc( 3181f52228b8SJoe Beteta sizeof (struct skd_fitmsg_context) * skdev->num_fitmsg_context, 3182f52228b8SJoe Beteta KM_SLEEP); 3183f52228b8SJoe Beteta 3184f52228b8SJoe Beteta for (i = 0; i < skdev->num_fitmsg_context; i++) { 3185f52228b8SJoe Beteta struct skd_fitmsg_context *skmsg; 3186f52228b8SJoe Beteta 3187f52228b8SJoe Beteta skmsg = &skdev->skmsg_table[i]; 3188f52228b8SJoe Beteta 3189f52228b8SJoe Beteta skmsg->id = i + SKD_ID_FIT_MSG; 3190f52228b8SJoe Beteta 3191f52228b8SJoe Beteta skmsg->state = SKD_MSG_STATE_IDLE; 3192f52228b8SJoe Beteta 3193f52228b8SJoe Beteta mem = &skmsg->mb_dma_address; 3194f52228b8SJoe Beteta mem->size = SKD_N_FITMSG_BYTES + 64; 3195f52228b8SJoe Beteta 3196f52228b8SJoe Beteta skmsg->msg_buf = skd_alloc_dma_mem(skdev, mem, ATYPE_64BIT); 3197f52228b8SJoe Beteta 3198f52228b8SJoe Beteta if (NULL == skmsg->msg_buf) { 3199f52228b8SJoe Beteta rc = -ENOMEM; 3200f52228b8SJoe Beteta i++; 3201f52228b8SJoe Beteta break; 3202f52228b8SJoe Beteta } 3203f52228b8SJoe Beteta 3204f52228b8SJoe Beteta skmsg->offset = 0; 3205f52228b8SJoe Beteta 3206f52228b8SJoe Beteta bzero(skmsg->msg_buf, SKD_N_FITMSG_BYTES); 3207f52228b8SJoe Beteta 3208f52228b8SJoe Beteta skmsg->next = &skmsg[1]; 3209f52228b8SJoe Beteta } 3210f52228b8SJoe Beteta 3211f52228b8SJoe Beteta /* Free list is in order starting with the 0th entry. */ 3212f52228b8SJoe Beteta skdev->skmsg_table[i - 1].next = NULL; 3213f52228b8SJoe Beteta skdev->skmsg_free_list = skdev->skmsg_table; 3214f52228b8SJoe Beteta 3215f52228b8SJoe Beteta return (rc); 3216f52228b8SJoe Beteta } 3217f52228b8SJoe Beteta 3218f52228b8SJoe Beteta /* 3219f52228b8SJoe Beteta * 3220f52228b8SJoe Beteta * Name: skd_cons_skreq, allocates space for the skreq table. 3221f52228b8SJoe Beteta * 3222f52228b8SJoe Beteta * Inputs: skdev - device state structure. 3223f52228b8SJoe Beteta * 3224f52228b8SJoe Beteta * Returns: -ENOMEM if no memory otherwise NULL. 3225f52228b8SJoe Beteta * 3226f52228b8SJoe Beteta */ 3227f52228b8SJoe Beteta static int 3228f52228b8SJoe Beteta skd_cons_skreq(struct skd_device *skdev) 3229f52228b8SJoe Beteta { 3230f52228b8SJoe Beteta int rc = 0; 3231f52228b8SJoe Beteta uint32_t i; 3232f52228b8SJoe Beteta 3233f52228b8SJoe Beteta Dcmn_err(CE_NOTE, 3234f52228b8SJoe Beteta "skreq_table kmem_zalloc, struct %lu, count %u total %lu", 3235f52228b8SJoe Beteta (ulong_t)sizeof (struct skd_request_context), 3236f52228b8SJoe Beteta skdev->num_req_context, 3237f52228b8SJoe Beteta (ulong_t) (sizeof (struct skd_request_context) * 3238f52228b8SJoe Beteta skdev->num_req_context)); 3239f52228b8SJoe Beteta 3240f52228b8SJoe Beteta skdev->skreq_table = (struct skd_request_context *)kmem_zalloc( 3241f52228b8SJoe Beteta sizeof (struct skd_request_context) * skdev->num_req_context, 3242f52228b8SJoe Beteta KM_SLEEP); 3243f52228b8SJoe Beteta 3244f52228b8SJoe Beteta for (i = 0; i < skdev->num_req_context; i++) { 3245f52228b8SJoe Beteta struct skd_request_context *skreq; 3246f52228b8SJoe Beteta 3247f52228b8SJoe Beteta skreq = &skdev->skreq_table[i]; 3248f52228b8SJoe Beteta 3249f52228b8SJoe Beteta skreq->id = (uint16_t)(i + SKD_ID_RW_REQUEST); 3250f52228b8SJoe Beteta skreq->state = SKD_REQ_STATE_IDLE; 3251f52228b8SJoe Beteta 3252f52228b8SJoe Beteta skreq->sksg_list = skd_cons_sg_list(skdev, 3253f52228b8SJoe Beteta skdev->sgs_per_request, 3254f52228b8SJoe Beteta &skreq->sksg_dma_address); 3255f52228b8SJoe Beteta 3256f52228b8SJoe Beteta if (NULL == skreq->sksg_list) { 3257f52228b8SJoe Beteta rc = -ENOMEM; 3258f52228b8SJoe Beteta goto err_out; 3259f52228b8SJoe Beteta } 3260f52228b8SJoe Beteta 3261f52228b8SJoe Beteta skreq->next = &skreq[1]; 3262f52228b8SJoe Beteta } 3263f52228b8SJoe Beteta 3264f52228b8SJoe Beteta /* Free list is in order starting with the 0th entry. */ 3265f52228b8SJoe Beteta skdev->skreq_table[i - 1].next = NULL; 3266f52228b8SJoe Beteta skdev->skreq_free_list = skdev->skreq_table; 3267f52228b8SJoe Beteta 3268f52228b8SJoe Beteta err_out: 3269f52228b8SJoe Beteta return (rc); 3270f52228b8SJoe Beteta } 3271f52228b8SJoe Beteta 3272f52228b8SJoe Beteta /* 3273f52228b8SJoe Beteta * 3274f52228b8SJoe Beteta * Name: skd_cons_sksb, allocates space for the skspcl msg buf 3275f52228b8SJoe Beteta * and data buf. 3276f52228b8SJoe Beteta * 3277f52228b8SJoe Beteta * Inputs: skdev - device state structure. 3278f52228b8SJoe Beteta * 3279f52228b8SJoe Beteta * Returns: -ENOMEM if no memory otherwise NULL. 3280f52228b8SJoe Beteta * 3281f52228b8SJoe Beteta */ 3282f52228b8SJoe Beteta static int 3283f52228b8SJoe Beteta skd_cons_sksb(struct skd_device *skdev) 3284f52228b8SJoe Beteta { 3285f52228b8SJoe Beteta int rc = 0; 3286f52228b8SJoe Beteta struct skd_special_context *skspcl; 3287f52228b8SJoe Beteta dma_mem_t *mem; 3288f52228b8SJoe Beteta uint32_t nbytes; 3289f52228b8SJoe Beteta 3290f52228b8SJoe Beteta skspcl = &skdev->internal_skspcl; 3291f52228b8SJoe Beteta 3292f52228b8SJoe Beteta skspcl->req.id = 0 + SKD_ID_INTERNAL; 3293f52228b8SJoe Beteta skspcl->req.state = SKD_REQ_STATE_IDLE; 3294f52228b8SJoe Beteta 3295f52228b8SJoe Beteta nbytes = SKD_N_INTERNAL_BYTES; 3296f52228b8SJoe Beteta 3297f52228b8SJoe Beteta mem = &skspcl->db_dma_address; 3298f52228b8SJoe Beteta mem->size = nbytes; 3299f52228b8SJoe Beteta 3300f52228b8SJoe Beteta /* data_buf's DMA pointer is skspcl->db_dma_address */ 3301f52228b8SJoe Beteta skspcl->data_buf = skd_alloc_dma_mem(skdev, mem, ATYPE_64BIT); 3302f52228b8SJoe Beteta if (skspcl->data_buf == NULL) { 3303f52228b8SJoe Beteta rc = -ENOMEM; 3304f52228b8SJoe Beteta goto err_out; 3305f52228b8SJoe Beteta } 3306f52228b8SJoe Beteta 3307f52228b8SJoe Beteta bzero(skspcl->data_buf, nbytes); 3308f52228b8SJoe Beteta 3309f52228b8SJoe Beteta nbytes = SKD_N_SPECIAL_FITMSG_BYTES; 3310f52228b8SJoe Beteta 3311f52228b8SJoe Beteta mem = &skspcl->mb_dma_address; 3312f52228b8SJoe Beteta mem->size = nbytes; 3313f52228b8SJoe Beteta 3314f52228b8SJoe Beteta /* msg_buf DMA pointer is skspcl->mb_dma_address */ 3315f52228b8SJoe Beteta skspcl->msg_buf = skd_alloc_dma_mem(skdev, mem, ATYPE_64BIT); 3316f52228b8SJoe Beteta if (skspcl->msg_buf == NULL) { 3317f52228b8SJoe Beteta rc = -ENOMEM; 3318f52228b8SJoe Beteta goto err_out; 3319f52228b8SJoe Beteta } 3320f52228b8SJoe Beteta 3321f52228b8SJoe Beteta 3322f52228b8SJoe Beteta bzero(skspcl->msg_buf, nbytes); 3323f52228b8SJoe Beteta 3324f52228b8SJoe Beteta skspcl->req.sksg_list = skd_cons_sg_list(skdev, 1, 3325f52228b8SJoe Beteta &skspcl->req.sksg_dma_address); 3326f52228b8SJoe Beteta 3327f52228b8SJoe Beteta 3328f52228b8SJoe Beteta if (skspcl->req.sksg_list == NULL) { 3329f52228b8SJoe Beteta rc = -ENOMEM; 3330f52228b8SJoe Beteta goto err_out; 3331f52228b8SJoe Beteta } 3332f52228b8SJoe Beteta 3333f52228b8SJoe Beteta if (skd_format_internal_skspcl(skdev) == 0) { 3334f52228b8SJoe Beteta rc = -EINVAL; 3335f52228b8SJoe Beteta goto err_out; 3336f52228b8SJoe Beteta } 3337f52228b8SJoe Beteta 3338f52228b8SJoe Beteta err_out: 3339f52228b8SJoe Beteta return (rc); 3340f52228b8SJoe Beteta } 3341f52228b8SJoe Beteta 3342f52228b8SJoe Beteta /* 3343f52228b8SJoe Beteta * 3344f52228b8SJoe Beteta * Name: skd_cons_sg_list, allocates the S/G list. 3345f52228b8SJoe Beteta * 3346f52228b8SJoe Beteta * Inputs: skdev - device state structure. 3347f52228b8SJoe Beteta * n_sg - Number of scatter-gather entries. 3348f52228b8SJoe Beteta * ret_dma_addr - S/G list DMA pointer. 3349f52228b8SJoe Beteta * 3350f52228b8SJoe Beteta * Returns: A list of FIT message descriptors. 3351f52228b8SJoe Beteta * 3352f52228b8SJoe Beteta */ 3353f52228b8SJoe Beteta static struct fit_sg_descriptor 3354f52228b8SJoe Beteta *skd_cons_sg_list(struct skd_device *skdev, 3355f52228b8SJoe Beteta uint32_t n_sg, dma_mem_t *ret_dma_addr) 3356f52228b8SJoe Beteta { 3357f52228b8SJoe Beteta struct fit_sg_descriptor *sg_list; 3358f52228b8SJoe Beteta uint32_t nbytes; 3359f52228b8SJoe Beteta dma_mem_t *mem; 3360f52228b8SJoe Beteta 3361f52228b8SJoe Beteta nbytes = sizeof (*sg_list) * n_sg; 3362f52228b8SJoe Beteta 3363f52228b8SJoe Beteta mem = ret_dma_addr; 3364f52228b8SJoe Beteta mem->size = nbytes; 3365f52228b8SJoe Beteta 3366f52228b8SJoe Beteta /* sg_list's DMA pointer is *ret_dma_addr */ 3367f52228b8SJoe Beteta sg_list = skd_alloc_dma_mem(skdev, mem, ATYPE_32BIT); 3368f52228b8SJoe Beteta 3369f52228b8SJoe Beteta if (sg_list != NULL) { 3370f52228b8SJoe Beteta uint64_t dma_address = ret_dma_addr->cookie.dmac_laddress; 3371f52228b8SJoe Beteta uint32_t i; 3372f52228b8SJoe Beteta 3373f52228b8SJoe Beteta bzero(sg_list, nbytes); 3374f52228b8SJoe Beteta 3375f52228b8SJoe Beteta for (i = 0; i < n_sg - 1; i++) { 3376f52228b8SJoe Beteta uint64_t ndp_off; 3377f52228b8SJoe Beteta ndp_off = (i + 1) * sizeof (struct fit_sg_descriptor); 3378f52228b8SJoe Beteta 3379f52228b8SJoe Beteta sg_list[i].next_desc_ptr = dma_address + ndp_off; 3380f52228b8SJoe Beteta } 3381f52228b8SJoe Beteta sg_list[i].next_desc_ptr = 0LL; 3382f52228b8SJoe Beteta } 3383f52228b8SJoe Beteta 3384f52228b8SJoe Beteta return (sg_list); 3385f52228b8SJoe Beteta } 3386f52228b8SJoe Beteta 3387f52228b8SJoe Beteta /* 3388f52228b8SJoe Beteta * DESTRUCT (FREE) 3389f52228b8SJoe Beteta */ 3390f52228b8SJoe Beteta 3391f52228b8SJoe Beteta static void skd_free_skcomp(struct skd_device *skdev); 3392f52228b8SJoe Beteta static void skd_free_skmsg(struct skd_device *skdev); 3393f52228b8SJoe Beteta static void skd_free_skreq(struct skd_device *skdev); 3394f52228b8SJoe Beteta static void skd_free_sksb(struct skd_device *skdev); 3395f52228b8SJoe Beteta 3396f52228b8SJoe Beteta static void skd_free_sg_list(struct skd_device *skdev, 3397f52228b8SJoe Beteta struct fit_sg_descriptor *sg_list, 3398f52228b8SJoe Beteta uint32_t n_sg, dma_mem_t dma_addr); 3399f52228b8SJoe Beteta 3400f52228b8SJoe Beteta /* 3401f52228b8SJoe Beteta * 3402f52228b8SJoe Beteta * Name: skd_destruct, call various rouines to deallocate 3403f52228b8SJoe Beteta * space acquired during initialization. 3404f52228b8SJoe Beteta * 3405f52228b8SJoe Beteta * Inputs: skdev - device state structure. 3406f52228b8SJoe Beteta * 3407f52228b8SJoe Beteta * Returns: Nothing. 3408f52228b8SJoe Beteta * 3409f52228b8SJoe Beteta */ 3410f52228b8SJoe Beteta static void 3411f52228b8SJoe Beteta skd_destruct(struct skd_device *skdev) 3412f52228b8SJoe Beteta { 3413f52228b8SJoe Beteta if (skdev == NULL) { 3414f52228b8SJoe Beteta return; 3415f52228b8SJoe Beteta } 3416f52228b8SJoe Beteta 3417f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "destruct sksb"); 3418f52228b8SJoe Beteta skd_free_sksb(skdev); 3419f52228b8SJoe Beteta 3420f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "destruct skreq"); 3421f52228b8SJoe Beteta skd_free_skreq(skdev); 3422f52228b8SJoe Beteta 3423f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "destruct skmsg"); 3424f52228b8SJoe Beteta skd_free_skmsg(skdev); 3425f52228b8SJoe Beteta 3426f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "destruct skcomp"); 3427f52228b8SJoe Beteta skd_free_skcomp(skdev); 3428f52228b8SJoe Beteta 3429f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "DESTRUCT VICTORY"); 3430f52228b8SJoe Beteta } 3431f52228b8SJoe Beteta 3432f52228b8SJoe Beteta /* 3433f52228b8SJoe Beteta * 3434f52228b8SJoe Beteta * Name: skd_free_skcomp, deallocates skcomp table DMA resources. 3435f52228b8SJoe Beteta * 3436f52228b8SJoe Beteta * Inputs: skdev - device state structure. 3437f52228b8SJoe Beteta * 3438f52228b8SJoe Beteta * Returns: Nothing. 3439f52228b8SJoe Beteta * 3440f52228b8SJoe Beteta */ 3441f52228b8SJoe Beteta static void 3442f52228b8SJoe Beteta skd_free_skcomp(struct skd_device *skdev) 3443f52228b8SJoe Beteta { 3444f52228b8SJoe Beteta if (skdev->skcomp_table != NULL) { 3445f52228b8SJoe Beteta skd_free_phys(skdev, &skdev->cq_dma_address); 3446f52228b8SJoe Beteta } 3447f52228b8SJoe Beteta 3448f52228b8SJoe Beteta skdev->skcomp_table = NULL; 3449f52228b8SJoe Beteta } 3450f52228b8SJoe Beteta 3451f52228b8SJoe Beteta /* 3452f52228b8SJoe Beteta * 3453f52228b8SJoe Beteta * Name: skd_free_skmsg, deallocates skmsg table DMA resources. 3454f52228b8SJoe Beteta * 3455f52228b8SJoe Beteta * Inputs: skdev - device state structure. 3456f52228b8SJoe Beteta * 3457f52228b8SJoe Beteta * Returns: Nothing. 3458f52228b8SJoe Beteta * 3459f52228b8SJoe Beteta */ 3460f52228b8SJoe Beteta static void 3461f52228b8SJoe Beteta skd_free_skmsg(struct skd_device *skdev) 3462f52228b8SJoe Beteta { 3463f52228b8SJoe Beteta uint32_t i; 3464f52228b8SJoe Beteta 3465f52228b8SJoe Beteta if (NULL == skdev->skmsg_table) 3466f52228b8SJoe Beteta return; 3467f52228b8SJoe Beteta 3468f52228b8SJoe Beteta for (i = 0; i < skdev->num_fitmsg_context; i++) { 3469f52228b8SJoe Beteta struct skd_fitmsg_context *skmsg; 3470f52228b8SJoe Beteta 3471f52228b8SJoe Beteta skmsg = &skdev->skmsg_table[i]; 3472f52228b8SJoe Beteta 3473f52228b8SJoe Beteta if (skmsg->msg_buf != NULL) { 3474f52228b8SJoe Beteta skd_free_phys(skdev, &skmsg->mb_dma_address); 3475f52228b8SJoe Beteta } 3476f52228b8SJoe Beteta 3477f52228b8SJoe Beteta 3478f52228b8SJoe Beteta skmsg->msg_buf = NULL; 3479f52228b8SJoe Beteta } 3480f52228b8SJoe Beteta 3481f52228b8SJoe Beteta kmem_free(skdev->skmsg_table, sizeof (struct skd_fitmsg_context) * 3482f52228b8SJoe Beteta skdev->num_fitmsg_context); 3483f52228b8SJoe Beteta 3484f52228b8SJoe Beteta skdev->skmsg_table = NULL; 3485f52228b8SJoe Beteta 3486f52228b8SJoe Beteta } 3487f52228b8SJoe Beteta 3488f52228b8SJoe Beteta /* 3489f52228b8SJoe Beteta * 3490f52228b8SJoe Beteta * Name: skd_free_skreq, deallocates skspcl table DMA resources. 3491f52228b8SJoe Beteta * 3492f52228b8SJoe Beteta * Inputs: skdev - device state structure. 3493f52228b8SJoe Beteta * 3494f52228b8SJoe Beteta * Returns: Nothing. 3495f52228b8SJoe Beteta * 3496f52228b8SJoe Beteta */ 3497f52228b8SJoe Beteta static void 3498f52228b8SJoe Beteta skd_free_skreq(struct skd_device *skdev) 3499f52228b8SJoe Beteta { 3500f52228b8SJoe Beteta uint32_t i; 3501f52228b8SJoe Beteta 3502f52228b8SJoe Beteta if (NULL == skdev->skreq_table) 3503f52228b8SJoe Beteta return; 3504f52228b8SJoe Beteta 3505f52228b8SJoe Beteta for (i = 0; i < skdev->num_req_context; i++) { 3506f52228b8SJoe Beteta struct skd_request_context *skreq; 3507f52228b8SJoe Beteta 3508f52228b8SJoe Beteta skreq = &skdev->skreq_table[i]; 3509f52228b8SJoe Beteta 3510f52228b8SJoe Beteta skd_free_sg_list(skdev, skreq->sksg_list, 3511f52228b8SJoe Beteta skdev->sgs_per_request, skreq->sksg_dma_address); 3512f52228b8SJoe Beteta 3513f52228b8SJoe Beteta skreq->sksg_list = NULL; 3514f52228b8SJoe Beteta } 3515f52228b8SJoe Beteta 3516f52228b8SJoe Beteta kmem_free(skdev->skreq_table, sizeof (struct skd_request_context) * 3517f52228b8SJoe Beteta skdev->num_req_context); 3518f52228b8SJoe Beteta 3519f52228b8SJoe Beteta skdev->skreq_table = NULL; 3520f52228b8SJoe Beteta 3521f52228b8SJoe Beteta } 3522f52228b8SJoe Beteta 3523f52228b8SJoe Beteta /* 3524f52228b8SJoe Beteta * 3525f52228b8SJoe Beteta * Name: skd_free_sksb, deallocates skspcl data buf and 3526f52228b8SJoe Beteta * msg buf DMA resources. 3527f52228b8SJoe Beteta * 3528f52228b8SJoe Beteta * Inputs: skdev - device state structure. 3529f52228b8SJoe Beteta * 3530f52228b8SJoe Beteta * Returns: Nothing. 3531f52228b8SJoe Beteta * 3532f52228b8SJoe Beteta */ 3533f52228b8SJoe Beteta static void 3534f52228b8SJoe Beteta skd_free_sksb(struct skd_device *skdev) 3535f52228b8SJoe Beteta { 3536f52228b8SJoe Beteta struct skd_special_context *skspcl; 3537f52228b8SJoe Beteta 3538f52228b8SJoe Beteta skspcl = &skdev->internal_skspcl; 3539f52228b8SJoe Beteta 3540f52228b8SJoe Beteta if (skspcl->data_buf != NULL) { 3541f52228b8SJoe Beteta skd_free_phys(skdev, &skspcl->db_dma_address); 3542f52228b8SJoe Beteta } 3543f52228b8SJoe Beteta 3544f52228b8SJoe Beteta skspcl->data_buf = NULL; 3545f52228b8SJoe Beteta 3546f52228b8SJoe Beteta if (skspcl->msg_buf != NULL) { 3547f52228b8SJoe Beteta skd_free_phys(skdev, &skspcl->mb_dma_address); 3548f52228b8SJoe Beteta } 3549f52228b8SJoe Beteta 3550f52228b8SJoe Beteta skspcl->msg_buf = NULL; 3551f52228b8SJoe Beteta 3552f52228b8SJoe Beteta skd_free_sg_list(skdev, skspcl->req.sksg_list, 1, 3553f52228b8SJoe Beteta skspcl->req.sksg_dma_address); 3554f52228b8SJoe Beteta 3555f52228b8SJoe Beteta skspcl->req.sksg_list = NULL; 3556f52228b8SJoe Beteta } 3557f52228b8SJoe Beteta 3558f52228b8SJoe Beteta /* 3559f52228b8SJoe Beteta * 3560f52228b8SJoe Beteta * Name: skd_free_sg_list, deallocates S/G DMA resources. 3561f52228b8SJoe Beteta * 3562f52228b8SJoe Beteta * Inputs: skdev - device state structure. 3563f52228b8SJoe Beteta * sg_list - S/G list itself. 3564f52228b8SJoe Beteta * n_sg - nukmber of segments 3565f52228b8SJoe Beteta * dma_addr - S/G list DMA address. 3566f52228b8SJoe Beteta * 3567f52228b8SJoe Beteta * Returns: Nothing. 3568f52228b8SJoe Beteta * 3569f52228b8SJoe Beteta */ 3570f52228b8SJoe Beteta /* ARGSUSED */ /* Upstream common source with other platforms. */ 3571f52228b8SJoe Beteta static void 3572f52228b8SJoe Beteta skd_free_sg_list(struct skd_device *skdev, 3573f52228b8SJoe Beteta struct fit_sg_descriptor *sg_list, 3574f52228b8SJoe Beteta uint32_t n_sg, dma_mem_t dma_addr) 3575f52228b8SJoe Beteta { 3576f52228b8SJoe Beteta if (sg_list != NULL) { 3577f52228b8SJoe Beteta skd_free_phys(skdev, &dma_addr); 3578f52228b8SJoe Beteta } 3579f52228b8SJoe Beteta } 3580f52228b8SJoe Beteta 3581f52228b8SJoe Beteta /* 3582f52228b8SJoe Beteta * 3583f52228b8SJoe Beteta * Name: skd_queue, queues the I/O request. 3584f52228b8SJoe Beteta * 3585f52228b8SJoe Beteta * Inputs: skdev - device state structure. 3586f52228b8SJoe Beteta * pbuf - I/O request 3587f52228b8SJoe Beteta * 3588f52228b8SJoe Beteta * Returns: Nothing. 3589f52228b8SJoe Beteta * 3590f52228b8SJoe Beteta */ 3591f52228b8SJoe Beteta static void 3592f52228b8SJoe Beteta skd_queue(skd_device_t *skdev, skd_buf_private_t *pbuf) 3593f52228b8SJoe Beteta { 3594f52228b8SJoe Beteta struct waitqueue *waitq; 3595f52228b8SJoe Beteta 3596f52228b8SJoe Beteta ASSERT(skdev != NULL); 3597f52228b8SJoe Beteta ASSERT(pbuf != NULL); 3598f52228b8SJoe Beteta 3599f52228b8SJoe Beteta ASSERT(WAITQ_LOCK_HELD(skdev)); 3600f52228b8SJoe Beteta 3601f52228b8SJoe Beteta waitq = &skdev->waitqueue; 3602f52228b8SJoe Beteta 3603f52228b8SJoe Beteta if (SIMPLEQ_EMPTY(waitq)) 3604f52228b8SJoe Beteta SIMPLEQ_INSERT_HEAD(waitq, pbuf, sq); 3605f52228b8SJoe Beteta else 3606f52228b8SJoe Beteta SIMPLEQ_INSERT_TAIL(waitq, pbuf, sq); 3607f52228b8SJoe Beteta } 3608f52228b8SJoe Beteta 3609f52228b8SJoe Beteta /* 3610f52228b8SJoe Beteta * 3611f52228b8SJoe Beteta * Name: skd_list_skreq, displays the skreq table entries. 3612f52228b8SJoe Beteta * 3613f52228b8SJoe Beteta * Inputs: skdev - device state structure. 3614f52228b8SJoe Beteta * list - flag, if true displays the entry address. 3615f52228b8SJoe Beteta * 3616f52228b8SJoe Beteta * Returns: Returns number of skmsg entries found. 3617f52228b8SJoe Beteta * 3618f52228b8SJoe Beteta */ 3619f52228b8SJoe Beteta /* ARGSUSED */ /* Upstream common source with other platforms. */ 3620f52228b8SJoe Beteta static int 3621f52228b8SJoe Beteta skd_list_skreq(skd_device_t *skdev, int list) 3622f52228b8SJoe Beteta { 3623f52228b8SJoe Beteta int inx = 0; 3624f52228b8SJoe Beteta struct skd_request_context *skreq; 3625f52228b8SJoe Beteta 3626f52228b8SJoe Beteta if (list) { 3627f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "skreq_table[0]\n"); 3628f52228b8SJoe Beteta 3629f52228b8SJoe Beteta skreq = &skdev->skreq_table[0]; 3630f52228b8SJoe Beteta while (skreq) { 3631f52228b8SJoe Beteta if (list) 3632f52228b8SJoe Beteta Dcmn_err(CE_NOTE, 3633f52228b8SJoe Beteta "%d: skreq=%p state=%d id=%x fid=%x " 3634f52228b8SJoe Beteta "pbuf=%p dir=%d comp=%d\n", 3635f52228b8SJoe Beteta inx, (void *)skreq, skreq->state, 3636f52228b8SJoe Beteta skreq->id, skreq->fitmsg_id, 3637f52228b8SJoe Beteta (void *)skreq->pbuf, 3638f52228b8SJoe Beteta skreq->sg_data_dir, skreq->did_complete); 3639f52228b8SJoe Beteta inx++; 3640f52228b8SJoe Beteta skreq = skreq->next; 3641f52228b8SJoe Beteta } 3642f52228b8SJoe Beteta } 3643f52228b8SJoe Beteta 3644f52228b8SJoe Beteta inx = 0; 3645f52228b8SJoe Beteta skreq = skdev->skreq_free_list; 3646f52228b8SJoe Beteta 3647f52228b8SJoe Beteta if (list) 3648f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "skreq_free_list\n"); 3649f52228b8SJoe Beteta while (skreq) { 3650f52228b8SJoe Beteta if (list) 3651f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "%d: skreq=%p state=%d id=%x fid=%x " 3652f52228b8SJoe Beteta "pbuf=%p dir=%d\n", inx, (void *)skreq, 3653f52228b8SJoe Beteta skreq->state, skreq->id, skreq->fitmsg_id, 3654f52228b8SJoe Beteta (void *)skreq->pbuf, skreq->sg_data_dir); 3655f52228b8SJoe Beteta inx++; 3656f52228b8SJoe Beteta skreq = skreq->next; 3657f52228b8SJoe Beteta } 3658f52228b8SJoe Beteta 3659f52228b8SJoe Beteta return (inx); 3660f52228b8SJoe Beteta } 3661f52228b8SJoe Beteta 3662f52228b8SJoe Beteta /* 3663f52228b8SJoe Beteta * 3664f52228b8SJoe Beteta * Name: skd_list_skmsg, displays the skmsg table entries. 3665f52228b8SJoe Beteta * 3666f52228b8SJoe Beteta * Inputs: skdev - device state structure. 3667f52228b8SJoe Beteta * list - flag, if true displays the entry address. 3668f52228b8SJoe Beteta * 3669f52228b8SJoe Beteta * Returns: Returns number of skmsg entries found. 3670f52228b8SJoe Beteta * 3671f52228b8SJoe Beteta */ 3672f52228b8SJoe Beteta static int 3673f52228b8SJoe Beteta skd_list_skmsg(skd_device_t *skdev, int list) 3674f52228b8SJoe Beteta { 3675f52228b8SJoe Beteta int inx = 0; 3676f52228b8SJoe Beteta struct skd_fitmsg_context *skmsgp; 3677f52228b8SJoe Beteta 3678f52228b8SJoe Beteta skmsgp = &skdev->skmsg_table[0]; 3679f52228b8SJoe Beteta 3680f52228b8SJoe Beteta if (list) { 3681f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "skmsg_table[0]\n"); 3682f52228b8SJoe Beteta 3683f52228b8SJoe Beteta while (skmsgp) { 3684f52228b8SJoe Beteta if (list) 3685f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "%d: skmsgp=%p id=%x outs=%d " 3686f52228b8SJoe Beteta "l=%d o=%d nxt=%p\n", inx, (void *)skmsgp, 3687f52228b8SJoe Beteta skmsgp->id, skmsgp->outstanding, 3688f52228b8SJoe Beteta skmsgp->length, skmsgp->offset, 3689f52228b8SJoe Beteta (void *)skmsgp->next); 3690f52228b8SJoe Beteta inx++; 3691f52228b8SJoe Beteta skmsgp = skmsgp->next; 3692f52228b8SJoe Beteta } 3693f52228b8SJoe Beteta } 3694f52228b8SJoe Beteta 3695f52228b8SJoe Beteta inx = 0; 3696f52228b8SJoe Beteta if (list) 3697f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "skmsg_free_list\n"); 3698f52228b8SJoe Beteta skmsgp = skdev->skmsg_free_list; 3699f52228b8SJoe Beteta while (skmsgp) { 3700f52228b8SJoe Beteta if (list) 3701f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "%d: skmsgp=%p id=%x outs=%d l=%d " 3702f52228b8SJoe Beteta "o=%d nxt=%p\n", 3703f52228b8SJoe Beteta inx, (void *)skmsgp, skmsgp->id, 3704f52228b8SJoe Beteta skmsgp->outstanding, skmsgp->length, 3705f52228b8SJoe Beteta skmsgp->offset, (void *)skmsgp->next); 3706f52228b8SJoe Beteta inx++; 3707f52228b8SJoe Beteta skmsgp = skmsgp->next; 3708f52228b8SJoe Beteta } 3709f52228b8SJoe Beteta 3710f52228b8SJoe Beteta return (inx); 3711f52228b8SJoe Beteta } 3712f52228b8SJoe Beteta 3713f52228b8SJoe Beteta /* 3714f52228b8SJoe Beteta * 3715f52228b8SJoe Beteta * Name: skd_get_queue_pbuf, retrieves top of queue entry and 3716f52228b8SJoe Beteta * delinks entry from the queue. 3717f52228b8SJoe Beteta * 3718f52228b8SJoe Beteta * Inputs: skdev - device state structure. 3719f52228b8SJoe Beteta * drive - device number 3720f52228b8SJoe Beteta * 3721f52228b8SJoe Beteta * Returns: Returns the top of the job queue entry. 3722f52228b8SJoe Beteta * 3723f52228b8SJoe Beteta */ 3724f52228b8SJoe Beteta static skd_buf_private_t 3725f52228b8SJoe Beteta *skd_get_queued_pbuf(skd_device_t *skdev) 3726f52228b8SJoe Beteta { 3727f52228b8SJoe Beteta skd_buf_private_t *pbuf; 3728f52228b8SJoe Beteta 3729f52228b8SJoe Beteta ASSERT(WAITQ_LOCK_HELD(skdev)); 3730f52228b8SJoe Beteta pbuf = SIMPLEQ_FIRST(&skdev->waitqueue); 3731f52228b8SJoe Beteta if (pbuf != NULL) 3732f52228b8SJoe Beteta SIMPLEQ_REMOVE_HEAD(&skdev->waitqueue, sq); 3733f52228b8SJoe Beteta return (pbuf); 3734f52228b8SJoe Beteta } 3735f52228b8SJoe Beteta 3736f52228b8SJoe Beteta /* 3737f52228b8SJoe Beteta * PCI DRIVER GLUE 3738f52228b8SJoe Beteta */ 3739f52228b8SJoe Beteta 3740f52228b8SJoe Beteta /* 3741f52228b8SJoe Beteta * 3742f52228b8SJoe Beteta * Name: skd_pci_info, logs certain device PCI info. 3743f52228b8SJoe Beteta * 3744f52228b8SJoe Beteta * Inputs: skdev - device state structure. 3745f52228b8SJoe Beteta * 3746f52228b8SJoe Beteta * Returns: str which contains the device speed info.. 3747f52228b8SJoe Beteta * 3748f52228b8SJoe Beteta */ 3749f52228b8SJoe Beteta static char * 3750f52228b8SJoe Beteta skd_pci_info(struct skd_device *skdev, char *str, size_t len) 3751f52228b8SJoe Beteta { 3752f52228b8SJoe Beteta int pcie_reg; 3753f52228b8SJoe Beteta 3754f52228b8SJoe Beteta str[0] = '\0'; 3755f52228b8SJoe Beteta 3756f52228b8SJoe Beteta pcie_reg = skd_pci_find_capability(skdev, PCI_CAP_ID_EXP); 3757f52228b8SJoe Beteta 3758f52228b8SJoe Beteta if (pcie_reg) { 3759f52228b8SJoe Beteta uint16_t lstat, lspeed, lwidth; 3760f52228b8SJoe Beteta 3761f52228b8SJoe Beteta pcie_reg += 0x12; 3762f52228b8SJoe Beteta lstat = pci_config_get16(skdev->pci_handle, pcie_reg); 3763f52228b8SJoe Beteta lspeed = lstat & (0xF); 3764f52228b8SJoe Beteta lwidth = (lstat & 0x3F0) >> 4; 3765f52228b8SJoe Beteta 3766f52228b8SJoe Beteta (void) snprintf(str, len, "PCIe (%s rev %d)", 3767f52228b8SJoe Beteta lspeed == 1 ? "2.5GT/s" : 3768f52228b8SJoe Beteta lspeed == 2 ? "5.0GT/s" : "<unknown>", 3769f52228b8SJoe Beteta lwidth); 3770f52228b8SJoe Beteta } 3771f52228b8SJoe Beteta 3772f52228b8SJoe Beteta return (str); 3773f52228b8SJoe Beteta } 3774f52228b8SJoe Beteta 3775f52228b8SJoe Beteta /* 3776f52228b8SJoe Beteta * MODULE GLUE 3777f52228b8SJoe Beteta */ 3778f52228b8SJoe Beteta 3779f52228b8SJoe Beteta /* 3780f52228b8SJoe Beteta * 3781f52228b8SJoe Beteta * Name: skd_init, initializes certain values. 3782f52228b8SJoe Beteta * 3783f52228b8SJoe Beteta * Inputs: skdev - device state structure. 3784f52228b8SJoe Beteta * 3785f52228b8SJoe Beteta * Returns: Zero. 3786f52228b8SJoe Beteta * 3787f52228b8SJoe Beteta */ 3788f52228b8SJoe Beteta /* ARGSUSED */ /* Upstream common source with other platforms. */ 3789f52228b8SJoe Beteta static int 3790f52228b8SJoe Beteta skd_init(skd_device_t *skdev) 3791f52228b8SJoe Beteta { 3792f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "skd_init: v%s-b%s\n", DRV_VERSION, DRV_BUILD_ID); 3793f52228b8SJoe Beteta 3794f52228b8SJoe Beteta if (skd_max_queue_depth < 1 || 3795f52228b8SJoe Beteta skd_max_queue_depth > SKD_MAX_QUEUE_DEPTH) { 3796f52228b8SJoe Beteta cmn_err(CE_NOTE, "skd_max_q_depth %d invalid, re-set to %d\n", 3797f52228b8SJoe Beteta skd_max_queue_depth, SKD_MAX_QUEUE_DEPTH_DEFAULT); 3798f52228b8SJoe Beteta skd_max_queue_depth = SKD_MAX_QUEUE_DEPTH_DEFAULT; 3799f52228b8SJoe Beteta } 3800f52228b8SJoe Beteta 3801f52228b8SJoe Beteta if (skd_max_req_per_msg < 1 || skd_max_req_per_msg > 14) { 3802f52228b8SJoe Beteta cmn_err(CE_NOTE, "skd_max_req_per_msg %d invalid, set to %d\n", 3803f52228b8SJoe Beteta skd_max_req_per_msg, SKD_MAX_REQ_PER_MSG_DEFAULT); 3804f52228b8SJoe Beteta skd_max_req_per_msg = SKD_MAX_REQ_PER_MSG_DEFAULT; 3805f52228b8SJoe Beteta } 3806f52228b8SJoe Beteta 3807f52228b8SJoe Beteta 3808f52228b8SJoe Beteta if (skd_sgs_per_request < 1 || skd_sgs_per_request > 4096) { 3809f52228b8SJoe Beteta cmn_err(CE_NOTE, "skd_sg_per_request %d invalid, set to %d\n", 3810f52228b8SJoe Beteta skd_sgs_per_request, SKD_N_SG_PER_REQ_DEFAULT); 3811f52228b8SJoe Beteta skd_sgs_per_request = SKD_N_SG_PER_REQ_DEFAULT; 3812f52228b8SJoe Beteta } 3813f52228b8SJoe Beteta 3814f52228b8SJoe Beteta if (skd_dbg_level < 0 || skd_dbg_level > 2) { 3815f52228b8SJoe Beteta cmn_err(CE_NOTE, "skd_dbg_level %d invalid, re-set to %d\n", 3816f52228b8SJoe Beteta skd_dbg_level, 0); 3817f52228b8SJoe Beteta skd_dbg_level = 0; 3818f52228b8SJoe Beteta } 3819f52228b8SJoe Beteta 3820f52228b8SJoe Beteta return (0); 3821f52228b8SJoe Beteta } 3822f52228b8SJoe Beteta 3823f52228b8SJoe Beteta /* 3824f52228b8SJoe Beteta * 3825f52228b8SJoe Beteta * Name: skd_exit, exits the driver & logs the fact. 3826f52228b8SJoe Beteta * 3827f52228b8SJoe Beteta * Inputs: none. 3828f52228b8SJoe Beteta * 3829f52228b8SJoe Beteta * Returns: Nothing. 3830f52228b8SJoe Beteta * 3831f52228b8SJoe Beteta */ 3832f52228b8SJoe Beteta static void 3833f52228b8SJoe Beteta skd_exit(void) 3834f52228b8SJoe Beteta { 3835f52228b8SJoe Beteta cmn_err(CE_NOTE, "skd v%s unloading", DRV_VERSION); 3836f52228b8SJoe Beteta } 3837f52228b8SJoe Beteta 3838f52228b8SJoe Beteta /* 3839f52228b8SJoe Beteta * 3840f52228b8SJoe Beteta * Name: skd_drive_state_to_str, converts binary drive state 3841f52228b8SJoe Beteta * to its corresponding string value. 3842f52228b8SJoe Beteta * 3843f52228b8SJoe Beteta * Inputs: Drive state. 3844f52228b8SJoe Beteta * 3845f52228b8SJoe Beteta * Returns: String representing drive state. 3846f52228b8SJoe Beteta * 3847f52228b8SJoe Beteta */ 3848f52228b8SJoe Beteta const char * 3849f52228b8SJoe Beteta skd_drive_state_to_str(int state) 3850f52228b8SJoe Beteta { 3851f52228b8SJoe Beteta switch (state) { 3852f52228b8SJoe Beteta case FIT_SR_DRIVE_OFFLINE: return ("OFFLINE"); 3853f52228b8SJoe Beteta case FIT_SR_DRIVE_INIT: return ("INIT"); 3854f52228b8SJoe Beteta case FIT_SR_DRIVE_ONLINE: return ("ONLINE"); 3855f52228b8SJoe Beteta case FIT_SR_DRIVE_BUSY: return ("BUSY"); 3856f52228b8SJoe Beteta case FIT_SR_DRIVE_FAULT: return ("FAULT"); 3857f52228b8SJoe Beteta case FIT_SR_DRIVE_DEGRADED: return ("DEGRADED"); 3858f52228b8SJoe Beteta case FIT_SR_PCIE_LINK_DOWN: return ("LINK_DOWN"); 3859f52228b8SJoe Beteta case FIT_SR_DRIVE_SOFT_RESET: return ("SOFT_RESET"); 3860f52228b8SJoe Beteta case FIT_SR_DRIVE_NEED_FW_DOWNLOAD: return ("NEED_FW"); 3861f52228b8SJoe Beteta case FIT_SR_DRIVE_INIT_FAULT: return ("INIT_FAULT"); 3862f52228b8SJoe Beteta case FIT_SR_DRIVE_BUSY_SANITIZE:return ("BUSY_SANITIZE"); 3863f52228b8SJoe Beteta case FIT_SR_DRIVE_BUSY_ERASE: return ("BUSY_ERASE"); 3864f52228b8SJoe Beteta case FIT_SR_DRIVE_FW_BOOTING: return ("FW_BOOTING"); 3865f52228b8SJoe Beteta default: return ("???"); 3866f52228b8SJoe Beteta } 3867f52228b8SJoe Beteta } 3868f52228b8SJoe Beteta 3869f52228b8SJoe Beteta /* 3870f52228b8SJoe Beteta * 3871f52228b8SJoe Beteta * Name: skd_skdev_state_to_str, converts binary driver state 3872f52228b8SJoe Beteta * to its corresponding string value. 3873f52228b8SJoe Beteta * 3874f52228b8SJoe Beteta * Inputs: Driver state. 3875f52228b8SJoe Beteta * 3876f52228b8SJoe Beteta * Returns: String representing driver state. 3877f52228b8SJoe Beteta * 3878f52228b8SJoe Beteta */ 3879f52228b8SJoe Beteta static const char * 3880f52228b8SJoe Beteta skd_skdev_state_to_str(enum skd_drvr_state state) 3881f52228b8SJoe Beteta { 3882f52228b8SJoe Beteta switch (state) { 3883f52228b8SJoe Beteta case SKD_DRVR_STATE_LOAD: return ("LOAD"); 3884f52228b8SJoe Beteta case SKD_DRVR_STATE_IDLE: return ("IDLE"); 3885f52228b8SJoe Beteta case SKD_DRVR_STATE_BUSY: return ("BUSY"); 3886f52228b8SJoe Beteta case SKD_DRVR_STATE_STARTING: return ("STARTING"); 3887f52228b8SJoe Beteta case SKD_DRVR_STATE_ONLINE: return ("ONLINE"); 3888f52228b8SJoe Beteta case SKD_DRVR_STATE_PAUSING: return ("PAUSING"); 3889f52228b8SJoe Beteta case SKD_DRVR_STATE_PAUSED: return ("PAUSED"); 3890f52228b8SJoe Beteta case SKD_DRVR_STATE_DRAINING_TIMEOUT: return ("DRAINING_TIMEOUT"); 3891f52228b8SJoe Beteta case SKD_DRVR_STATE_RESTARTING: return ("RESTARTING"); 3892f52228b8SJoe Beteta case SKD_DRVR_STATE_RESUMING: return ("RESUMING"); 3893f52228b8SJoe Beteta case SKD_DRVR_STATE_STOPPING: return ("STOPPING"); 3894f52228b8SJoe Beteta case SKD_DRVR_STATE_SYNCING: return ("SYNCING"); 3895f52228b8SJoe Beteta case SKD_DRVR_STATE_FAULT: return ("FAULT"); 3896f52228b8SJoe Beteta case SKD_DRVR_STATE_DISAPPEARED: return ("DISAPPEARED"); 3897f52228b8SJoe Beteta case SKD_DRVR_STATE_BUSY_ERASE: return ("BUSY_ERASE"); 3898f52228b8SJoe Beteta case SKD_DRVR_STATE_BUSY_SANITIZE:return ("BUSY_SANITIZE"); 3899f52228b8SJoe Beteta case SKD_DRVR_STATE_BUSY_IMMINENT: return ("BUSY_IMMINENT"); 3900f52228b8SJoe Beteta case SKD_DRVR_STATE_WAIT_BOOT: return ("WAIT_BOOT"); 3901f52228b8SJoe Beteta 3902f52228b8SJoe Beteta default: return ("???"); 3903f52228b8SJoe Beteta } 3904f52228b8SJoe Beteta } 3905f52228b8SJoe Beteta 3906f52228b8SJoe Beteta /* 3907f52228b8SJoe Beteta * 3908f52228b8SJoe Beteta * Name: skd_skmsg_state_to_str, converts binary driver state 3909f52228b8SJoe Beteta * to its corresponding string value. 3910f52228b8SJoe Beteta * 3911f52228b8SJoe Beteta * Inputs: Msg state. 3912f52228b8SJoe Beteta * 3913f52228b8SJoe Beteta * Returns: String representing msg state. 3914f52228b8SJoe Beteta * 3915f52228b8SJoe Beteta */ 3916f52228b8SJoe Beteta static const char * 3917f52228b8SJoe Beteta skd_skmsg_state_to_str(enum skd_fit_msg_state state) 3918f52228b8SJoe Beteta { 3919f52228b8SJoe Beteta switch (state) { 3920f52228b8SJoe Beteta case SKD_MSG_STATE_IDLE: return ("IDLE"); 3921f52228b8SJoe Beteta case SKD_MSG_STATE_BUSY: return ("BUSY"); 3922f52228b8SJoe Beteta default: return ("???"); 3923f52228b8SJoe Beteta } 3924f52228b8SJoe Beteta } 3925f52228b8SJoe Beteta 3926f52228b8SJoe Beteta /* 3927f52228b8SJoe Beteta * 3928f52228b8SJoe Beteta * Name: skd_skreq_state_to_str, converts binary req state 3929f52228b8SJoe Beteta * to its corresponding string value. 3930f52228b8SJoe Beteta * 3931f52228b8SJoe Beteta * Inputs: Req state. 3932f52228b8SJoe Beteta * 3933f52228b8SJoe Beteta * Returns: String representing req state. 3934f52228b8SJoe Beteta * 3935f52228b8SJoe Beteta */ 3936f52228b8SJoe Beteta static const char * 3937f52228b8SJoe Beteta skd_skreq_state_to_str(enum skd_req_state state) 3938f52228b8SJoe Beteta { 3939f52228b8SJoe Beteta switch (state) { 3940f52228b8SJoe Beteta case SKD_REQ_STATE_IDLE: return ("IDLE"); 3941f52228b8SJoe Beteta case SKD_REQ_STATE_SETUP: return ("SETUP"); 3942f52228b8SJoe Beteta case SKD_REQ_STATE_BUSY: return ("BUSY"); 3943f52228b8SJoe Beteta case SKD_REQ_STATE_COMPLETED: return ("COMPLETED"); 3944f52228b8SJoe Beteta case SKD_REQ_STATE_TIMEOUT: return ("TIMEOUT"); 3945f52228b8SJoe Beteta case SKD_REQ_STATE_ABORTED: return ("ABORTED"); 3946f52228b8SJoe Beteta default: return ("???"); 3947f52228b8SJoe Beteta } 3948f52228b8SJoe Beteta } 3949f52228b8SJoe Beteta 3950f52228b8SJoe Beteta /* 3951f52228b8SJoe Beteta * 3952f52228b8SJoe Beteta * Name: skd_log_skdev, logs device state & parameters. 3953f52228b8SJoe Beteta * 3954f52228b8SJoe Beteta * Inputs: skdev - device state structure. 3955f52228b8SJoe Beteta * event - event (string) to log. 3956f52228b8SJoe Beteta * 3957f52228b8SJoe Beteta * Returns: Nothing. 3958f52228b8SJoe Beteta * 3959f52228b8SJoe Beteta */ 3960f52228b8SJoe Beteta static void 3961f52228b8SJoe Beteta skd_log_skdev(struct skd_device *skdev, const char *event) 3962f52228b8SJoe Beteta { 3963f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "log_skdev(%s) skdev=%p event='%s'", 3964f52228b8SJoe Beteta skdev->name, (void *)skdev, event); 3965f52228b8SJoe Beteta Dcmn_err(CE_NOTE, " drive_state=%s(%d) driver_state=%s(%d)", 3966f52228b8SJoe Beteta skd_drive_state_to_str(skdev->drive_state), skdev->drive_state, 3967f52228b8SJoe Beteta skd_skdev_state_to_str(skdev->state), skdev->state); 3968f52228b8SJoe Beteta Dcmn_err(CE_NOTE, " busy=%d limit=%d soft=%d hard=%d lowat=%d", 3969f52228b8SJoe Beteta skdev->queue_depth_busy, skdev->queue_depth_limit, 3970f52228b8SJoe Beteta skdev->soft_queue_depth_limit, skdev->hard_queue_depth_limit, 3971f52228b8SJoe Beteta skdev->queue_depth_lowat); 3972f52228b8SJoe Beteta Dcmn_err(CE_NOTE, " timestamp=0x%x cycle=%d cycle_ix=%d", 3973f52228b8SJoe Beteta skdev->timeout_stamp, skdev->skcomp_cycle, skdev->skcomp_ix); 3974f52228b8SJoe Beteta } 3975f52228b8SJoe Beteta 3976f52228b8SJoe Beteta /* 3977f52228b8SJoe Beteta * 3978f52228b8SJoe Beteta * Name: skd_log_skmsg, logs the skmsg event. 3979f52228b8SJoe Beteta * 3980f52228b8SJoe Beteta * Inputs: skdev - device state structure. 3981f52228b8SJoe Beteta * skmsg - FIT message structure. 3982f52228b8SJoe Beteta * event - event string to log. 3983f52228b8SJoe Beteta * 3984f52228b8SJoe Beteta * Returns: Nothing. 3985f52228b8SJoe Beteta * 3986f52228b8SJoe Beteta */ 3987f52228b8SJoe Beteta static void 3988f52228b8SJoe Beteta skd_log_skmsg(struct skd_device *skdev, 3989f52228b8SJoe Beteta struct skd_fitmsg_context *skmsg, const char *event) 3990f52228b8SJoe Beteta { 3991f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "log_skmsg:(%s) skmsg=%p event='%s'", 3992f52228b8SJoe Beteta skdev->name, (void *)skmsg, event); 3993f52228b8SJoe Beteta Dcmn_err(CE_NOTE, " state=%s(%d) id=0x%04x length=%d", 3994f52228b8SJoe Beteta skd_skmsg_state_to_str(skmsg->state), skmsg->state, 3995f52228b8SJoe Beteta skmsg->id, skmsg->length); 3996f52228b8SJoe Beteta } 3997f52228b8SJoe Beteta 3998f52228b8SJoe Beteta /* 3999f52228b8SJoe Beteta * 4000f52228b8SJoe Beteta * Name: skd_log_skreq, logs the skreq event. 4001f52228b8SJoe Beteta * 4002f52228b8SJoe Beteta * Inputs: skdev - device state structure. 4003f52228b8SJoe Beteta * skreq -skreq structure. 4004f52228b8SJoe Beteta * event - event string to log. 4005f52228b8SJoe Beteta * 4006f52228b8SJoe Beteta * Returns: Nothing. 4007f52228b8SJoe Beteta * 4008f52228b8SJoe Beteta */ 4009f52228b8SJoe Beteta static void 4010f52228b8SJoe Beteta skd_log_skreq(struct skd_device *skdev, 4011f52228b8SJoe Beteta struct skd_request_context *skreq, const char *event) 4012f52228b8SJoe Beteta { 4013f52228b8SJoe Beteta skd_buf_private_t *pbuf; 4014f52228b8SJoe Beteta 4015f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "log_skreq: (%s) skreq=%p pbuf=%p event='%s'", 4016f52228b8SJoe Beteta skdev->name, (void *)skreq, (void *)skreq->pbuf, event); 4017f52228b8SJoe Beteta 4018f52228b8SJoe Beteta Dcmn_err(CE_NOTE, " state=%s(%d) id=0x%04x fitmsg=0x%04x", 4019f52228b8SJoe Beteta skd_skreq_state_to_str(skreq->state), skreq->state, 4020f52228b8SJoe Beteta skreq->id, skreq->fitmsg_id); 4021f52228b8SJoe Beteta Dcmn_err(CE_NOTE, " timo=0x%x sg_dir=%d n_sg=%d", 4022f52228b8SJoe Beteta skreq->timeout_stamp, skreq->sg_data_dir, skreq->n_sg); 4023f52228b8SJoe Beteta 4024f52228b8SJoe Beteta if ((pbuf = skreq->pbuf) != NULL) { 4025f52228b8SJoe Beteta uint32_t lba, count; 4026f52228b8SJoe Beteta lba = pbuf->x_xfer->x_blkno; 4027f52228b8SJoe Beteta count = pbuf->x_xfer->x_nblks; 4028f52228b8SJoe Beteta Dcmn_err(CE_NOTE, " pbuf=%p lba=%u(0x%x) count=%u(0x%x) ", 4029f52228b8SJoe Beteta (void *)pbuf, lba, lba, count, count); 4030f52228b8SJoe Beteta Dcmn_err(CE_NOTE, " dir=%s " 4031f52228b8SJoe Beteta " intrs=%" PRId64 " qdepth=%d", 4032f52228b8SJoe Beteta (pbuf->dir & B_READ) ? "Read" : "Write", 4033f52228b8SJoe Beteta skdev->intr_cntr, skdev->queue_depth_busy); 4034f52228b8SJoe Beteta } else { 4035f52228b8SJoe Beteta Dcmn_err(CE_NOTE, " req=NULL\n"); 4036f52228b8SJoe Beteta } 4037f52228b8SJoe Beteta } 4038f52228b8SJoe Beteta 4039f52228b8SJoe Beteta /* 4040f52228b8SJoe Beteta * 4041f52228b8SJoe Beteta * Name: skd_init_mutex, initializes all mutexes. 4042f52228b8SJoe Beteta * 4043f52228b8SJoe Beteta * Inputs: skdev - device state structure. 4044f52228b8SJoe Beteta * 4045f52228b8SJoe Beteta * Returns: DDI_FAILURE on failure otherwise DDI_SUCCESS. 4046f52228b8SJoe Beteta * 4047f52228b8SJoe Beteta */ 4048f52228b8SJoe Beteta static int 4049f52228b8SJoe Beteta skd_init_mutex(skd_device_t *skdev) 4050f52228b8SJoe Beteta { 4051f52228b8SJoe Beteta void *intr; 4052f52228b8SJoe Beteta 4053f52228b8SJoe Beteta Dcmn_err(CE_CONT, "(%s%d): init_mutex flags=%x", DRV_NAME, 4054f52228b8SJoe Beteta skdev->instance, skdev->flags); 4055f52228b8SJoe Beteta 4056f52228b8SJoe Beteta intr = (void *)(uintptr_t)skdev->intr_pri; 4057f52228b8SJoe Beteta 4058f52228b8SJoe Beteta if (skdev->flags & SKD_MUTEX_INITED) 4059f52228b8SJoe Beteta cmn_err(CE_NOTE, "init_mutex: Oh-Oh - already INITED"); 4060f52228b8SJoe Beteta 4061f52228b8SJoe Beteta /* mutexes to protect the adapter state structure. */ 4062f52228b8SJoe Beteta mutex_init(&skdev->skd_lock_mutex, NULL, MUTEX_DRIVER, 4063f52228b8SJoe Beteta DDI_INTR_PRI(intr)); 4064f52228b8SJoe Beteta mutex_init(&skdev->skd_intr_mutex, NULL, MUTEX_DRIVER, 4065f52228b8SJoe Beteta DDI_INTR_PRI(intr)); 4066f52228b8SJoe Beteta mutex_init(&skdev->waitqueue_mutex, NULL, MUTEX_DRIVER, 4067f52228b8SJoe Beteta DDI_INTR_PRI(intr)); 4068f52228b8SJoe Beteta mutex_init(&skdev->skd_internalio_mutex, NULL, MUTEX_DRIVER, 4069f52228b8SJoe Beteta DDI_INTR_PRI(intr)); 4070f52228b8SJoe Beteta 4071f52228b8SJoe Beteta cv_init(&skdev->cv_waitq, NULL, CV_DRIVER, NULL); 4072f52228b8SJoe Beteta 4073f52228b8SJoe Beteta skdev->flags |= SKD_MUTEX_INITED; 4074f52228b8SJoe Beteta if (skdev->flags & SKD_MUTEX_DESTROYED) 4075f52228b8SJoe Beteta skdev->flags &= ~SKD_MUTEX_DESTROYED; 4076f52228b8SJoe Beteta 4077f52228b8SJoe Beteta Dcmn_err(CE_CONT, "init_mutex (%s%d): done, flags=%x", DRV_NAME, 4078f52228b8SJoe Beteta skdev->instance, skdev->flags); 4079f52228b8SJoe Beteta 4080f52228b8SJoe Beteta return (DDI_SUCCESS); 4081f52228b8SJoe Beteta } 4082f52228b8SJoe Beteta 4083f52228b8SJoe Beteta /* 4084f52228b8SJoe Beteta * 4085f52228b8SJoe Beteta * Name: skd_destroy_mutex, destroys all mutexes. 4086f52228b8SJoe Beteta * 4087f52228b8SJoe Beteta * Inputs: skdev - device state structure. 4088f52228b8SJoe Beteta * 4089f52228b8SJoe Beteta * Returns: Nothing. 4090f52228b8SJoe Beteta * 4091f52228b8SJoe Beteta */ 4092f52228b8SJoe Beteta static void 4093f52228b8SJoe Beteta skd_destroy_mutex(skd_device_t *skdev) 4094f52228b8SJoe Beteta { 4095f52228b8SJoe Beteta if ((skdev->flags & SKD_MUTEX_DESTROYED) == 0) { 4096f52228b8SJoe Beteta if (skdev->flags & SKD_MUTEX_INITED) { 4097f52228b8SJoe Beteta mutex_destroy(&skdev->waitqueue_mutex); 4098f52228b8SJoe Beteta mutex_destroy(&skdev->skd_intr_mutex); 4099f52228b8SJoe Beteta mutex_destroy(&skdev->skd_lock_mutex); 4100f52228b8SJoe Beteta mutex_destroy(&skdev->skd_internalio_mutex); 4101f52228b8SJoe Beteta 4102f52228b8SJoe Beteta cv_destroy(&skdev->cv_waitq); 4103f52228b8SJoe Beteta 4104f52228b8SJoe Beteta skdev->flags |= SKD_MUTEX_DESTROYED; 4105f52228b8SJoe Beteta 4106f52228b8SJoe Beteta if (skdev->flags & SKD_MUTEX_INITED) 4107f52228b8SJoe Beteta skdev->flags &= ~SKD_MUTEX_INITED; 4108f52228b8SJoe Beteta } 4109f52228b8SJoe Beteta } 4110f52228b8SJoe Beteta } 4111f52228b8SJoe Beteta 4112f52228b8SJoe Beteta /* 4113f52228b8SJoe Beteta * 4114f52228b8SJoe Beteta * Name: skd_setup_intr, setup the interrupt handling 4115f52228b8SJoe Beteta * 4116f52228b8SJoe Beteta * Inputs: skdev - device state structure. 4117f52228b8SJoe Beteta * intr_type - requested DDI interrupt type. 4118f52228b8SJoe Beteta * 4119f52228b8SJoe Beteta * Returns: DDI_FAILURE on failure otherwise DDI_SUCCESS. 4120f52228b8SJoe Beteta * 4121f52228b8SJoe Beteta */ 4122f52228b8SJoe Beteta static int 4123f52228b8SJoe Beteta skd_setup_intr(skd_device_t *skdev, int intr_type) 4124f52228b8SJoe Beteta { 4125f52228b8SJoe Beteta int32_t count = 0; 4126f52228b8SJoe Beteta int32_t avail = 0; 4127f52228b8SJoe Beteta int32_t actual = 0; 4128f52228b8SJoe Beteta int32_t ret; 4129f52228b8SJoe Beteta uint32_t i; 4130f52228b8SJoe Beteta 4131f52228b8SJoe Beteta Dcmn_err(CE_CONT, "(%s%d): setup_intr", DRV_NAME, skdev->instance); 4132f52228b8SJoe Beteta 4133f52228b8SJoe Beteta /* Get number of interrupts the platform h/w supports */ 4134f52228b8SJoe Beteta if (((ret = ddi_intr_get_nintrs(skdev->dip, intr_type, &count)) != 4135f52228b8SJoe Beteta DDI_SUCCESS) || count == 0) { 4136f52228b8SJoe Beteta cmn_err(CE_WARN, "!intr_setup failed, nintrs ret=%xh, cnt=%xh", 4137f52228b8SJoe Beteta ret, count); 4138f52228b8SJoe Beteta 4139f52228b8SJoe Beteta return (DDI_FAILURE); 4140f52228b8SJoe Beteta } 4141f52228b8SJoe Beteta 4142f52228b8SJoe Beteta /* Get number of available system interrupts */ 4143f52228b8SJoe Beteta if (((ret = ddi_intr_get_navail(skdev->dip, intr_type, &avail)) != 4144f52228b8SJoe Beteta DDI_SUCCESS) || avail == 0) { 4145f52228b8SJoe Beteta cmn_err(CE_WARN, "!intr_setup failed, navail ret=%xh, " 4146f52228b8SJoe Beteta "avail=%xh", ret, avail); 4147f52228b8SJoe Beteta 4148f52228b8SJoe Beteta return (DDI_FAILURE); 4149f52228b8SJoe Beteta } 4150f52228b8SJoe Beteta 4151f52228b8SJoe Beteta if (intr_type == DDI_INTR_TYPE_MSIX && avail < SKD_MSIX_MAXAIF) { 4152f52228b8SJoe Beteta cmn_err(CE_WARN, "!intr_setup failed, min MSI-X h/w vectors " 4153f52228b8SJoe Beteta "req'd: %d, avail: %d", 4154f52228b8SJoe Beteta SKD_MSIX_MAXAIF, count); 4155f52228b8SJoe Beteta 4156f52228b8SJoe Beteta return (DDI_FAILURE); 4157f52228b8SJoe Beteta } 4158f52228b8SJoe Beteta 4159f52228b8SJoe Beteta /* Allocate space for interrupt handles */ 4160f52228b8SJoe Beteta skdev->hsize = sizeof (ddi_intr_handle_t) * avail; 4161f52228b8SJoe Beteta skdev->htable = kmem_zalloc(skdev->hsize, KM_SLEEP); 4162f52228b8SJoe Beteta 4163f52228b8SJoe Beteta /* Allocate the interrupts */ 4164f52228b8SJoe Beteta if ((ret = ddi_intr_alloc(skdev->dip, skdev->htable, intr_type, 4165f52228b8SJoe Beteta 0, count, &actual, 0)) != DDI_SUCCESS) { 4166f52228b8SJoe Beteta cmn_err(CE_WARN, "!intr_setup failed, intr_alloc ret=%xh, " 4167f52228b8SJoe Beteta "count = %xh, " "actual=%xh", ret, count, actual); 4168f52228b8SJoe Beteta 4169f52228b8SJoe Beteta skd_release_intr(skdev); 4170f52228b8SJoe Beteta 4171f52228b8SJoe Beteta return (DDI_FAILURE); 4172f52228b8SJoe Beteta } 4173f52228b8SJoe Beteta 4174f52228b8SJoe Beteta skdev->intr_cnt = actual; 4175f52228b8SJoe Beteta 4176f52228b8SJoe Beteta if (intr_type == DDI_INTR_TYPE_FIXED) 4177f52228b8SJoe Beteta (void) ddi_intr_set_pri(skdev->htable[0], 10); 4178f52228b8SJoe Beteta 4179f52228b8SJoe Beteta /* Get interrupt priority */ 4180f52228b8SJoe Beteta if ((ret = ddi_intr_get_pri(skdev->htable[0], &skdev->intr_pri)) != 4181f52228b8SJoe Beteta DDI_SUCCESS) { 4182f52228b8SJoe Beteta cmn_err(CE_WARN, "!intr_setup failed, get_pri ret=%xh", ret); 4183f52228b8SJoe Beteta skd_release_intr(skdev); 4184f52228b8SJoe Beteta 4185f52228b8SJoe Beteta return (ret); 4186f52228b8SJoe Beteta } 4187f52228b8SJoe Beteta 4188f52228b8SJoe Beteta /* Add the interrupt handlers */ 4189f52228b8SJoe Beteta for (i = 0; i < actual; i++) { 4190f52228b8SJoe Beteta if ((ret = ddi_intr_add_handler(skdev->htable[i], 4191f52228b8SJoe Beteta skd_isr_aif, (void *)skdev, (void *)((ulong_t)i))) != 4192f52228b8SJoe Beteta DDI_SUCCESS) { 4193f52228b8SJoe Beteta cmn_err(CE_WARN, "!intr_setup failed, addh#=%xh, " 4194f52228b8SJoe Beteta "act=%xh, ret=%xh", i, actual, ret); 4195f52228b8SJoe Beteta skd_release_intr(skdev); 4196f52228b8SJoe Beteta 4197f52228b8SJoe Beteta return (ret); 4198f52228b8SJoe Beteta } 4199f52228b8SJoe Beteta } 4200f52228b8SJoe Beteta 4201f52228b8SJoe Beteta /* Setup mutexes */ 4202f52228b8SJoe Beteta if ((ret = skd_init_mutex(skdev)) != DDI_SUCCESS) { 4203f52228b8SJoe Beteta cmn_err(CE_WARN, "!intr_setup failed, mutex init ret=%xh", ret); 4204f52228b8SJoe Beteta skd_release_intr(skdev); 4205f52228b8SJoe Beteta 4206f52228b8SJoe Beteta return (ret); 4207f52228b8SJoe Beteta } 4208f52228b8SJoe Beteta 4209f52228b8SJoe Beteta /* Get the capabilities */ 4210f52228b8SJoe Beteta (void) ddi_intr_get_cap(skdev->htable[0], &skdev->intr_cap); 4211f52228b8SJoe Beteta 4212f52228b8SJoe Beteta /* Enable interrupts */ 4213f52228b8SJoe Beteta if (skdev->intr_cap & DDI_INTR_FLAG_BLOCK) { 4214f52228b8SJoe Beteta if ((ret = ddi_intr_block_enable(skdev->htable, 4215f52228b8SJoe Beteta skdev->intr_cnt)) != DDI_SUCCESS) { 4216f52228b8SJoe Beteta cmn_err(CE_WARN, "!failed, intr_setup block enable, " 4217f52228b8SJoe Beteta "ret=%xh", ret); 4218f52228b8SJoe Beteta skd_destroy_mutex(skdev); 4219f52228b8SJoe Beteta skd_release_intr(skdev); 4220f52228b8SJoe Beteta 4221f52228b8SJoe Beteta return (ret); 4222f52228b8SJoe Beteta } 4223f52228b8SJoe Beteta } else { 4224f52228b8SJoe Beteta for (i = 0; i < skdev->intr_cnt; i++) { 4225f52228b8SJoe Beteta if ((ret = ddi_intr_enable(skdev->htable[i])) != 4226f52228b8SJoe Beteta DDI_SUCCESS) { 4227f52228b8SJoe Beteta cmn_err(CE_WARN, "!intr_setup failed, " 4228f52228b8SJoe Beteta "intr enable, ret=%xh", ret); 4229f52228b8SJoe Beteta skd_destroy_mutex(skdev); 4230f52228b8SJoe Beteta skd_release_intr(skdev); 4231f52228b8SJoe Beteta 4232f52228b8SJoe Beteta return (ret); 4233f52228b8SJoe Beteta } 4234f52228b8SJoe Beteta } 4235f52228b8SJoe Beteta } 4236f52228b8SJoe Beteta 4237f52228b8SJoe Beteta if (intr_type == DDI_INTR_TYPE_FIXED) 4238f52228b8SJoe Beteta (void) ddi_intr_clr_mask(skdev->htable[0]); 4239f52228b8SJoe Beteta 4240f52228b8SJoe Beteta skdev->irq_type = intr_type; 4241f52228b8SJoe Beteta 4242f52228b8SJoe Beteta return (DDI_SUCCESS); 4243f52228b8SJoe Beteta } 4244f52228b8SJoe Beteta 4245f52228b8SJoe Beteta /* 4246f52228b8SJoe Beteta * 4247f52228b8SJoe Beteta * Name: skd_disable_intr, disable interrupt handling. 4248f52228b8SJoe Beteta * 4249f52228b8SJoe Beteta * Inputs: skdev - device state structure. 4250f52228b8SJoe Beteta * 4251f52228b8SJoe Beteta * Returns: Nothing. 4252f52228b8SJoe Beteta * 4253f52228b8SJoe Beteta */ 4254f52228b8SJoe Beteta static void 4255f52228b8SJoe Beteta skd_disable_intr(skd_device_t *skdev) 4256f52228b8SJoe Beteta { 4257f52228b8SJoe Beteta uint32_t i, rval; 4258f52228b8SJoe Beteta 4259f52228b8SJoe Beteta if (skdev->intr_cap & DDI_INTR_FLAG_BLOCK) { 4260f52228b8SJoe Beteta /* Remove AIF block interrupts (MSI/MSI-X) */ 4261f52228b8SJoe Beteta if ((rval = ddi_intr_block_disable(skdev->htable, 4262f52228b8SJoe Beteta skdev->intr_cnt)) != DDI_SUCCESS) { 4263f52228b8SJoe Beteta cmn_err(CE_WARN, "!failed intr block disable, rval=%x", 4264f52228b8SJoe Beteta rval); 4265f52228b8SJoe Beteta } 4266f52228b8SJoe Beteta } else { 4267f52228b8SJoe Beteta /* Remove AIF non-block interrupts (fixed). */ 4268f52228b8SJoe Beteta for (i = 0; i < skdev->intr_cnt; i++) { 4269f52228b8SJoe Beteta if ((rval = ddi_intr_disable(skdev->htable[i])) != 4270f52228b8SJoe Beteta DDI_SUCCESS) { 4271f52228b8SJoe Beteta cmn_err(CE_WARN, "!failed intr disable, " 4272f52228b8SJoe Beteta "intr#=%xh, " "rval=%xh", i, rval); 4273f52228b8SJoe Beteta } 4274f52228b8SJoe Beteta } 4275f52228b8SJoe Beteta } 4276f52228b8SJoe Beteta } 4277f52228b8SJoe Beteta 4278f52228b8SJoe Beteta /* 4279f52228b8SJoe Beteta * 4280f52228b8SJoe Beteta * Name: skd_release_intr, disables interrupt handling. 4281f52228b8SJoe Beteta * 4282f52228b8SJoe Beteta * Inputs: skdev - device state structure. 4283f52228b8SJoe Beteta * 4284f52228b8SJoe Beteta * Returns: Nothing. 4285f52228b8SJoe Beteta * 4286f52228b8SJoe Beteta */ 4287f52228b8SJoe Beteta static void 4288f52228b8SJoe Beteta skd_release_intr(skd_device_t *skdev) 4289f52228b8SJoe Beteta { 4290f52228b8SJoe Beteta int32_t i; 4291f52228b8SJoe Beteta int rval; 4292f52228b8SJoe Beteta 4293f52228b8SJoe Beteta 4294f52228b8SJoe Beteta Dcmn_err(CE_CONT, "REL_INTR intr_cnt=%d", skdev->intr_cnt); 4295f52228b8SJoe Beteta 4296f52228b8SJoe Beteta if (skdev->irq_type == 0) { 4297f52228b8SJoe Beteta Dcmn_err(CE_CONT, "release_intr: (%s%d): done", 4298f52228b8SJoe Beteta DRV_NAME, skdev->instance); 4299f52228b8SJoe Beteta return; 4300f52228b8SJoe Beteta } 4301f52228b8SJoe Beteta 4302f52228b8SJoe Beteta if (skdev->htable != NULL && skdev->hsize > 0) { 4303f52228b8SJoe Beteta i = (int32_t)skdev->hsize / (int32_t)sizeof (ddi_intr_handle_t); 4304f52228b8SJoe Beteta 4305f52228b8SJoe Beteta while (i-- > 0) { 4306f52228b8SJoe Beteta if (skdev->htable[i] == 0) { 4307f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "htable[%x]=0h", i); 4308f52228b8SJoe Beteta continue; 4309f52228b8SJoe Beteta } 4310f52228b8SJoe Beteta 4311f52228b8SJoe Beteta if ((rval = ddi_intr_disable(skdev->htable[i])) != 4312f52228b8SJoe Beteta DDI_SUCCESS) 4313f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "release_intr: intr_disable " 4314f52228b8SJoe Beteta "htable[%d], rval=%d", i, rval); 4315f52228b8SJoe Beteta 4316f52228b8SJoe Beteta if (i < skdev->intr_cnt) { 4317f52228b8SJoe Beteta if ((rval = ddi_intr_remove_handler( 4318f52228b8SJoe Beteta skdev->htable[i])) != DDI_SUCCESS) 4319f52228b8SJoe Beteta cmn_err(CE_WARN, "!release_intr: " 4320f52228b8SJoe Beteta "intr_remove_handler FAILED, " 4321f52228b8SJoe Beteta "rval=%d", rval); 4322f52228b8SJoe Beteta 4323f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "release_intr: " 4324f52228b8SJoe Beteta "remove_handler htable[%d]", i); 4325f52228b8SJoe Beteta } 4326f52228b8SJoe Beteta 4327f52228b8SJoe Beteta if ((rval = ddi_intr_free(skdev->htable[i])) != 4328f52228b8SJoe Beteta DDI_SUCCESS) 4329f52228b8SJoe Beteta cmn_err(CE_WARN, "!release_intr: intr_free " 4330f52228b8SJoe Beteta "FAILED, rval=%d", rval); 4331f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "release_intr: intr_free htable[%d]", 4332f52228b8SJoe Beteta i); 4333f52228b8SJoe Beteta } 4334f52228b8SJoe Beteta 4335f52228b8SJoe Beteta kmem_free(skdev->htable, skdev->hsize); 4336f52228b8SJoe Beteta skdev->htable = NULL; 4337f52228b8SJoe Beteta } 4338f52228b8SJoe Beteta 4339f52228b8SJoe Beteta skdev->hsize = 0; 4340f52228b8SJoe Beteta skdev->intr_cnt = 0; 4341f52228b8SJoe Beteta skdev->intr_pri = 0; 4342f52228b8SJoe Beteta skdev->intr_cap = 0; 4343f52228b8SJoe Beteta skdev->irq_type = 0; 4344f52228b8SJoe Beteta } 4345f52228b8SJoe Beteta 4346f52228b8SJoe Beteta /* 4347f52228b8SJoe Beteta * 4348f52228b8SJoe Beteta * Name: skd_dealloc_resources, deallocate resources allocated 4349f52228b8SJoe Beteta * during attach. 4350f52228b8SJoe Beteta * 4351f52228b8SJoe Beteta * Inputs: dip - DDI device info pointer. 4352f52228b8SJoe Beteta * skdev - device state structure. 4353f52228b8SJoe Beteta * seq - bit flag representing allocated item. 4354f52228b8SJoe Beteta * instance - device instance. 4355f52228b8SJoe Beteta * 4356f52228b8SJoe Beteta * Returns: Nothing. 4357f52228b8SJoe Beteta * 4358f52228b8SJoe Beteta */ 4359f52228b8SJoe Beteta /* ARGSUSED */ /* Upstream common source with other platforms. */ 4360f52228b8SJoe Beteta static void 4361f52228b8SJoe Beteta skd_dealloc_resources(dev_info_t *dip, skd_device_t *skdev, 4362f52228b8SJoe Beteta uint32_t seq, int instance) 4363f52228b8SJoe Beteta { 4364f52228b8SJoe Beteta 4365f52228b8SJoe Beteta if (skdev == NULL) 4366f52228b8SJoe Beteta return; 4367f52228b8SJoe Beteta 4368f52228b8SJoe Beteta if (seq & SKD_CONSTRUCTED) 4369f52228b8SJoe Beteta skd_destruct(skdev); 4370f52228b8SJoe Beteta 4371f52228b8SJoe Beteta if (seq & SKD_INTR_ADDED) { 4372f52228b8SJoe Beteta skd_disable_intr(skdev); 4373f52228b8SJoe Beteta skd_release_intr(skdev); 4374f52228b8SJoe Beteta } 4375f52228b8SJoe Beteta 4376f52228b8SJoe Beteta if (seq & SKD_DEV_IOBASE_MAPPED) 4377f52228b8SJoe Beteta ddi_regs_map_free(&skdev->dev_handle); 4378f52228b8SJoe Beteta 4379f52228b8SJoe Beteta if (seq & SKD_IOMAP_IOBASE_MAPPED) 4380f52228b8SJoe Beteta ddi_regs_map_free(&skdev->iomap_handle); 4381f52228b8SJoe Beteta 4382f52228b8SJoe Beteta if (seq & SKD_REGS_MAPPED) 4383f52228b8SJoe Beteta ddi_regs_map_free(&skdev->iobase_handle); 4384f52228b8SJoe Beteta 4385f52228b8SJoe Beteta if (seq & SKD_CONFIG_SPACE_SETUP) 4386f52228b8SJoe Beteta pci_config_teardown(&skdev->pci_handle); 4387f52228b8SJoe Beteta 4388f52228b8SJoe Beteta if (seq & SKD_SOFT_STATE_ALLOCED) { 4389f52228b8SJoe Beteta if (skdev->pathname && 4390f52228b8SJoe Beteta (skdev->flags & SKD_PATHNAME_ALLOCED)) { 4391f52228b8SJoe Beteta kmem_free(skdev->pathname, 4392f52228b8SJoe Beteta strlen(skdev->pathname)+1); 4393f52228b8SJoe Beteta } 4394f52228b8SJoe Beteta } 4395f52228b8SJoe Beteta 4396f52228b8SJoe Beteta if (skdev->s1120_devid) 4397f52228b8SJoe Beteta ddi_devid_free(skdev->s1120_devid); 4398f52228b8SJoe Beteta } 4399f52228b8SJoe Beteta 4400f52228b8SJoe Beteta /* 4401f52228b8SJoe Beteta * 4402f52228b8SJoe Beteta * Name: skd_setup_interrupt, sets up the appropriate interrupt type 4403f52228b8SJoe Beteta * msi, msix, or fixed. 4404f52228b8SJoe Beteta * 4405f52228b8SJoe Beteta * Inputs: skdev - device state structure. 4406f52228b8SJoe Beteta * 4407f52228b8SJoe Beteta * Returns: DDI_FAILURE on failure otherwise DDI_SUCCESS. 4408f52228b8SJoe Beteta * 4409f52228b8SJoe Beteta */ 4410f52228b8SJoe Beteta static int 4411f52228b8SJoe Beteta skd_setup_interrupts(skd_device_t *skdev) 4412f52228b8SJoe Beteta { 4413f52228b8SJoe Beteta int32_t rval = DDI_FAILURE; 4414f52228b8SJoe Beteta int32_t i; 4415f52228b8SJoe Beteta int32_t itypes = 0; 4416f52228b8SJoe Beteta 4417f52228b8SJoe Beteta /* 4418f52228b8SJoe Beteta * See what types of interrupts this adapter and platform support 4419f52228b8SJoe Beteta */ 4420f52228b8SJoe Beteta if ((i = ddi_intr_get_supported_types(skdev->dip, &itypes)) != 4421f52228b8SJoe Beteta DDI_SUCCESS) { 4422f52228b8SJoe Beteta cmn_err(CE_NOTE, "intr supported types failed, rval=%xh, ", i); 4423f52228b8SJoe Beteta return (DDI_FAILURE); 4424f52228b8SJoe Beteta } 4425f52228b8SJoe Beteta 4426f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "%s:supported interrupts types: %x", 4427f52228b8SJoe Beteta skdev->name, itypes); 4428f52228b8SJoe Beteta 4429f52228b8SJoe Beteta itypes &= skdev->irq_type; 4430f52228b8SJoe Beteta 4431f52228b8SJoe Beteta if (!skd_disable_msix && (itypes & DDI_INTR_TYPE_MSIX) && 4432f52228b8SJoe Beteta (rval = skd_setup_intr(skdev, DDI_INTR_TYPE_MSIX)) == DDI_SUCCESS) { 4433f52228b8SJoe Beteta cmn_err(CE_NOTE, "!%s: successful MSI-X setup", 4434f52228b8SJoe Beteta skdev->name); 4435f52228b8SJoe Beteta } else if (!skd_disable_msi && (itypes & DDI_INTR_TYPE_MSI) && 4436f52228b8SJoe Beteta (rval = skd_setup_intr(skdev, DDI_INTR_TYPE_MSI)) == DDI_SUCCESS) { 4437f52228b8SJoe Beteta cmn_err(CE_NOTE, "!%s: successful MSI setup", 4438f52228b8SJoe Beteta skdev->name); 4439f52228b8SJoe Beteta } else if ((itypes & DDI_INTR_TYPE_FIXED) && 4440f52228b8SJoe Beteta (rval = skd_setup_intr(skdev, DDI_INTR_TYPE_FIXED)) 4441f52228b8SJoe Beteta == DDI_SUCCESS) { 4442f52228b8SJoe Beteta cmn_err(CE_NOTE, "!%s: successful fixed intr setup", 4443f52228b8SJoe Beteta skdev->name); 4444f52228b8SJoe Beteta } else { 4445f52228b8SJoe Beteta cmn_err(CE_WARN, "!%s: no supported interrupt types", 4446f52228b8SJoe Beteta skdev->name); 4447f52228b8SJoe Beteta return (DDI_FAILURE); 4448f52228b8SJoe Beteta } 4449f52228b8SJoe Beteta 4450f52228b8SJoe Beteta Dcmn_err(CE_CONT, "%s: setup interrupts done", skdev->name); 4451f52228b8SJoe Beteta 4452f52228b8SJoe Beteta return (rval); 4453f52228b8SJoe Beteta } 4454f52228b8SJoe Beteta 4455f52228b8SJoe Beteta /* 4456f52228b8SJoe Beteta * 4457f52228b8SJoe Beteta * Name: skd_get_properties, retrieves properties from skd.conf. 4458f52228b8SJoe Beteta * 4459f52228b8SJoe Beteta * Inputs: skdev - device state structure. 4460f52228b8SJoe Beteta * dip - dev_info data structure. 4461f52228b8SJoe Beteta * 4462f52228b8SJoe Beteta * Returns: Nothing. 4463f52228b8SJoe Beteta * 4464f52228b8SJoe Beteta */ 4465f52228b8SJoe Beteta /* ARGSUSED */ /* Upstream common source with other platforms. */ 4466f52228b8SJoe Beteta static void 4467f52228b8SJoe Beteta skd_get_properties(dev_info_t *dip, skd_device_t *skdev) 4468f52228b8SJoe Beteta { 4469f52228b8SJoe Beteta int prop_value; 4470f52228b8SJoe Beteta 4471f52228b8SJoe Beteta skd_isr_type = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 4472f52228b8SJoe Beteta "intr-type-cap", -1); 4473f52228b8SJoe Beteta 4474f52228b8SJoe Beteta prop_value = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 4475f52228b8SJoe Beteta "max-scsi-reqs", -1); 4476f52228b8SJoe Beteta if (prop_value >= 1 && prop_value <= SKD_MAX_QUEUE_DEPTH) 4477f52228b8SJoe Beteta skd_max_queue_depth = prop_value; 4478f52228b8SJoe Beteta 4479f52228b8SJoe Beteta prop_value = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 4480f52228b8SJoe Beteta "max-scsi-reqs-per-msg", -1); 4481f52228b8SJoe Beteta if (prop_value >= 1 && prop_value <= SKD_MAX_REQ_PER_MSG) 4482f52228b8SJoe Beteta skd_max_req_per_msg = prop_value; 4483f52228b8SJoe Beteta 4484f52228b8SJoe Beteta prop_value = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 4485f52228b8SJoe Beteta "max-sgs-per-req", -1); 4486f52228b8SJoe Beteta if (prop_value >= 1 && prop_value <= SKD_MAX_N_SG_PER_REQ) 4487f52228b8SJoe Beteta skd_sgs_per_request = prop_value; 4488f52228b8SJoe Beteta 4489f52228b8SJoe Beteta prop_value = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 4490f52228b8SJoe Beteta "dbg-level", -1); 4491f52228b8SJoe Beteta if (prop_value >= 1 && prop_value <= 2) 4492f52228b8SJoe Beteta skd_dbg_level = prop_value; 4493f52228b8SJoe Beteta } 4494f52228b8SJoe Beteta 4495f52228b8SJoe Beteta /* 4496f52228b8SJoe Beteta * 4497f52228b8SJoe Beteta * Name: skd_wait_for_s1120, wait for device to finish 4498f52228b8SJoe Beteta * its initialization. 4499f52228b8SJoe Beteta * 4500f52228b8SJoe Beteta * Inputs: skdev - device state structure. 4501f52228b8SJoe Beteta * 4502f52228b8SJoe Beteta * Returns: DDI_SUCCESS or DDI_FAILURE. 4503f52228b8SJoe Beteta * 4504f52228b8SJoe Beteta */ 4505f52228b8SJoe Beteta static int 4506f52228b8SJoe Beteta skd_wait_for_s1120(skd_device_t *skdev) 4507f52228b8SJoe Beteta { 4508f52228b8SJoe Beteta clock_t cur_ticks, tmo; 4509f52228b8SJoe Beteta int loop_cntr = 0; 4510f52228b8SJoe Beteta int rc = DDI_FAILURE; 4511f52228b8SJoe Beteta 4512f52228b8SJoe Beteta mutex_enter(&skdev->skd_internalio_mutex); 4513f52228b8SJoe Beteta 4514f52228b8SJoe Beteta while (skdev->gendisk_on == 0) { 4515f52228b8SJoe Beteta cur_ticks = ddi_get_lbolt(); 4516f52228b8SJoe Beteta tmo = cur_ticks + drv_usectohz(MICROSEC); 4517f52228b8SJoe Beteta if (cv_timedwait(&skdev->cv_waitq, 4518f52228b8SJoe Beteta &skdev->skd_internalio_mutex, tmo) == -1) { 4519f52228b8SJoe Beteta /* Oops - timed out */ 4520f52228b8SJoe Beteta if (loop_cntr++ > 10) 4521f52228b8SJoe Beteta break; 4522f52228b8SJoe Beteta } 4523f52228b8SJoe Beteta } 4524f52228b8SJoe Beteta 4525f52228b8SJoe Beteta mutex_exit(&skdev->skd_internalio_mutex); 4526f52228b8SJoe Beteta 4527f52228b8SJoe Beteta if (skdev->gendisk_on == 1) 4528f52228b8SJoe Beteta rc = DDI_SUCCESS; 4529f52228b8SJoe Beteta 4530f52228b8SJoe Beteta return (rc); 4531f52228b8SJoe Beteta } 4532f52228b8SJoe Beteta 4533f52228b8SJoe Beteta /* 4534f52228b8SJoe Beteta * 4535f52228b8SJoe Beteta * Name: skd_update_props, updates certain device properties. 4536f52228b8SJoe Beteta * 4537f52228b8SJoe Beteta * Inputs: skdev - device state structure. 4538f52228b8SJoe Beteta * dip - dev info structure 4539f52228b8SJoe Beteta * 4540f52228b8SJoe Beteta * Returns: Nothing. 4541f52228b8SJoe Beteta * 4542f52228b8SJoe Beteta */ 4543f52228b8SJoe Beteta static void 4544f52228b8SJoe Beteta skd_update_props(skd_device_t *skdev, dev_info_t *dip) 4545f52228b8SJoe Beteta { 4546f52228b8SJoe Beteta int blksize = 512; 4547f52228b8SJoe Beteta 4548f52228b8SJoe Beteta if ((ddi_prop_update_int64(DDI_DEV_T_NONE, dip, "device-nblocks", 4549f52228b8SJoe Beteta skdev->Nblocks) != DDI_SUCCESS) || 4550f52228b8SJoe Beteta (ddi_prop_update_int(DDI_DEV_T_NONE, dip, "device-blksize", 4551f52228b8SJoe Beteta blksize) != DDI_SUCCESS)) { 4552f52228b8SJoe Beteta cmn_err(CE_NOTE, "%s: FAILED to create driver properties", 4553f52228b8SJoe Beteta skdev->name); 4554f52228b8SJoe Beteta } 4555f52228b8SJoe Beteta } 4556f52228b8SJoe Beteta 4557f52228b8SJoe Beteta /* 4558f52228b8SJoe Beteta * 4559f52228b8SJoe Beteta * Name: skd_setup_devid, sets up device ID info. 4560f52228b8SJoe Beteta * 4561f52228b8SJoe Beteta * Inputs: skdev - device state structure. 4562f52228b8SJoe Beteta * devid - Device ID for the DDI. 4563f52228b8SJoe Beteta * 4564f52228b8SJoe Beteta * Returns: DDI_SUCCESS or DDI_FAILURE. 4565f52228b8SJoe Beteta * 4566f52228b8SJoe Beteta */ 4567f52228b8SJoe Beteta static int 4568f52228b8SJoe Beteta skd_setup_devid(skd_device_t *skdev, ddi_devid_t *devid) 4569f52228b8SJoe Beteta { 4570f52228b8SJoe Beteta int rc, sz_model, sz_sn, sz; 4571f52228b8SJoe Beteta 4572*bef9e21aSHans Rosenfeld sz_model = scsi_ascii_inquiry_len(skdev->inq_product_id, 4573*bef9e21aSHans Rosenfeld strlen(skdev->inq_product_id)); 4574*bef9e21aSHans Rosenfeld sz_sn = scsi_ascii_inquiry_len(skdev->inq_serial_num, 4575*bef9e21aSHans Rosenfeld strlen(skdev->inq_serial_num)); 4576f52228b8SJoe Beteta sz = sz_model + sz_sn + 1; 4577f52228b8SJoe Beteta 4578*bef9e21aSHans Rosenfeld (void) snprintf(skdev->devid_str, sizeof (skdev->devid_str), 4579*bef9e21aSHans Rosenfeld "%.*s=%.*s", sz_model, skdev->inq_product_id, sz_sn, 4580*bef9e21aSHans Rosenfeld skdev->inq_serial_num); 4581f52228b8SJoe Beteta rc = ddi_devid_init(skdev->dip, DEVID_SCSI_SERIAL, sz, 4582f52228b8SJoe Beteta skdev->devid_str, devid); 4583f52228b8SJoe Beteta 4584f52228b8SJoe Beteta if (rc != DDI_SUCCESS) 4585f52228b8SJoe Beteta cmn_err(CE_WARN, "!%s: devid_init FAILED", skdev->name); 4586f52228b8SJoe Beteta 4587f52228b8SJoe Beteta return (rc); 4588f52228b8SJoe Beteta 4589f52228b8SJoe Beteta } 4590f52228b8SJoe Beteta 4591f52228b8SJoe Beteta /* 4592f52228b8SJoe Beteta * 4593f52228b8SJoe Beteta * Name: skd_bd_attach, attach to blkdev driver 4594f52228b8SJoe Beteta * 4595f52228b8SJoe Beteta * Inputs: skdev - device state structure. 4596f52228b8SJoe Beteta * dip - device info structure. 4597f52228b8SJoe Beteta * 4598f52228b8SJoe Beteta * Returns: DDI_SUCCESS or DDI_FAILURE. 4599f52228b8SJoe Beteta * 4600f52228b8SJoe Beteta */ 4601f52228b8SJoe Beteta static int 4602f52228b8SJoe Beteta skd_bd_attach(dev_info_t *dip, skd_device_t *skdev) 4603f52228b8SJoe Beteta { 4604f52228b8SJoe Beteta int rv; 4605f52228b8SJoe Beteta 4606f52228b8SJoe Beteta skdev->s_bdh = bd_alloc_handle(skdev, &skd_bd_ops, 4607f52228b8SJoe Beteta &skd_64bit_io_dma_attr, KM_SLEEP); 4608f52228b8SJoe Beteta 4609f52228b8SJoe Beteta if (skdev->s_bdh == NULL) { 4610f52228b8SJoe Beteta cmn_err(CE_WARN, "!skd_bd_attach: FAILED"); 4611f52228b8SJoe Beteta 4612f52228b8SJoe Beteta return (DDI_FAILURE); 4613f52228b8SJoe Beteta } 4614f52228b8SJoe Beteta 4615f52228b8SJoe Beteta rv = bd_attach_handle(dip, skdev->s_bdh); 4616f52228b8SJoe Beteta 4617f52228b8SJoe Beteta if (rv != DDI_SUCCESS) { 4618f52228b8SJoe Beteta cmn_err(CE_WARN, "!bd_attach_handle FAILED\n"); 4619f52228b8SJoe Beteta } else { 4620f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "bd_attach_handle OK\n"); 4621f52228b8SJoe Beteta skdev->bd_attached++; 4622f52228b8SJoe Beteta } 4623f52228b8SJoe Beteta 4624f52228b8SJoe Beteta return (rv); 4625f52228b8SJoe Beteta } 4626f52228b8SJoe Beteta 4627f52228b8SJoe Beteta /* 4628f52228b8SJoe Beteta * 4629f52228b8SJoe Beteta * Name: skd_bd_detach, detach from the blkdev driver. 4630f52228b8SJoe Beteta * 4631f52228b8SJoe Beteta * Inputs: skdev - device state structure. 4632f52228b8SJoe Beteta * 4633f52228b8SJoe Beteta * Returns: Nothing. 4634f52228b8SJoe Beteta * 4635f52228b8SJoe Beteta */ 4636f52228b8SJoe Beteta static void 4637f52228b8SJoe Beteta skd_bd_detach(skd_device_t *skdev) 4638f52228b8SJoe Beteta { 4639f52228b8SJoe Beteta if (skdev->bd_attached) 4640f52228b8SJoe Beteta (void) bd_detach_handle(skdev->s_bdh); 4641f52228b8SJoe Beteta 4642f52228b8SJoe Beteta bd_free_handle(skdev->s_bdh); 4643f52228b8SJoe Beteta } 4644f52228b8SJoe Beteta 4645f52228b8SJoe Beteta /* 4646f52228b8SJoe Beteta * 4647f52228b8SJoe Beteta * Name: skd_attach, attach sdk device driver 4648f52228b8SJoe Beteta * 4649f52228b8SJoe Beteta * Inputs: dip - device info structure. 4650f52228b8SJoe Beteta * cmd - DDI attach argument (ATTACH, RESUME, etc.) 4651f52228b8SJoe Beteta * 4652f52228b8SJoe Beteta * Returns: DDI_SUCCESS or DDI_FAILURE. 4653f52228b8SJoe Beteta * 4654f52228b8SJoe Beteta */ 4655f52228b8SJoe Beteta static int 4656f52228b8SJoe Beteta skd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 4657f52228b8SJoe Beteta { 4658f52228b8SJoe Beteta int instance; 4659f52228b8SJoe Beteta int nregs; 4660f52228b8SJoe Beteta skd_device_t *skdev = NULL; 4661f52228b8SJoe Beteta int inx; 4662f52228b8SJoe Beteta uint16_t cmd_reg; 4663f52228b8SJoe Beteta int progress = 0; 4664f52228b8SJoe Beteta char name[MAXPATHLEN]; 4665f52228b8SJoe Beteta off_t regsize; 4666f52228b8SJoe Beteta char pci_str[32]; 4667f52228b8SJoe Beteta char fw_version[8]; 4668f52228b8SJoe Beteta 4669f52228b8SJoe Beteta instance = ddi_get_instance(dip); 4670f52228b8SJoe Beteta 4671f52228b8SJoe Beteta (void) ddi_get_parent_data(dip); 4672f52228b8SJoe Beteta 4673f52228b8SJoe Beteta switch (cmd) { 4674f52228b8SJoe Beteta case DDI_ATTACH: 4675f52228b8SJoe Beteta break; 4676f52228b8SJoe Beteta 4677f52228b8SJoe Beteta case DDI_RESUME: 4678f52228b8SJoe Beteta /* Re-enable timer */ 4679f52228b8SJoe Beteta skd_start_timer(skdev); 4680f52228b8SJoe Beteta 4681f52228b8SJoe Beteta return (DDI_SUCCESS); 4682f52228b8SJoe Beteta 4683f52228b8SJoe Beteta default: 4684f52228b8SJoe Beteta return (DDI_FAILURE); 4685f52228b8SJoe Beteta } 4686f52228b8SJoe Beteta 4687f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "sTec S1120 Driver v%s Instance: %d", 4688f52228b8SJoe Beteta VERSIONSTR, instance); 4689f52228b8SJoe Beteta 4690f52228b8SJoe Beteta /* 4691f52228b8SJoe Beteta * Check that hardware is installed in a DMA-capable slot 4692f52228b8SJoe Beteta */ 4693f52228b8SJoe Beteta if (ddi_slaveonly(dip) == DDI_SUCCESS) { 4694f52228b8SJoe Beteta cmn_err(CE_WARN, "!%s%d: installed in a " 4695f52228b8SJoe Beteta "slot that isn't DMA-capable slot", DRV_NAME, instance); 4696f52228b8SJoe Beteta return (DDI_FAILURE); 4697f52228b8SJoe Beteta } 4698f52228b8SJoe Beteta 4699f52228b8SJoe Beteta /* 4700f52228b8SJoe Beteta * No support for high-level interrupts 4701f52228b8SJoe Beteta */ 4702f52228b8SJoe Beteta if (ddi_intr_hilevel(dip, 0) != 0) { 4703f52228b8SJoe Beteta cmn_err(CE_WARN, "!%s%d: High level interrupt not supported", 4704f52228b8SJoe Beteta DRV_NAME, instance); 4705f52228b8SJoe Beteta return (DDI_FAILURE); 4706f52228b8SJoe Beteta } 4707f52228b8SJoe Beteta 4708f52228b8SJoe Beteta /* 4709f52228b8SJoe Beteta * Allocate our per-device-instance structure 4710f52228b8SJoe Beteta */ 4711f52228b8SJoe Beteta if (ddi_soft_state_zalloc(skd_state, instance) != 4712f52228b8SJoe Beteta DDI_SUCCESS) { 4713f52228b8SJoe Beteta cmn_err(CE_WARN, "!%s%d: soft state zalloc failed ", 4714f52228b8SJoe Beteta DRV_NAME, instance); 4715f52228b8SJoe Beteta return (DDI_FAILURE); 4716f52228b8SJoe Beteta } 4717f52228b8SJoe Beteta 4718f52228b8SJoe Beteta progress |= SKD_SOFT_STATE_ALLOCED; 4719f52228b8SJoe Beteta 4720f52228b8SJoe Beteta skdev = ddi_get_soft_state(skd_state, instance); 4721f52228b8SJoe Beteta if (skdev == NULL) { 4722f52228b8SJoe Beteta cmn_err(CE_WARN, "!%s%d: Unable to get soft state structure", 4723f52228b8SJoe Beteta DRV_NAME, instance); 4724f52228b8SJoe Beteta goto skd_attach_failed; 4725f52228b8SJoe Beteta } 4726f52228b8SJoe Beteta 4727f52228b8SJoe Beteta (void) snprintf(skdev->name, sizeof (skdev->name), 4728f52228b8SJoe Beteta DRV_NAME "%d", instance); 4729f52228b8SJoe Beteta 4730f52228b8SJoe Beteta skdev->dip = dip; 4731f52228b8SJoe Beteta skdev->instance = instance; 4732f52228b8SJoe Beteta 4733f52228b8SJoe Beteta ddi_set_driver_private(dip, skdev); 4734f52228b8SJoe Beteta 4735f52228b8SJoe Beteta (void) ddi_pathname(dip, name); 4736f52228b8SJoe Beteta for (inx = strlen(name); inx; inx--) { 4737f52228b8SJoe Beteta if (name[inx] == ',') { 4738f52228b8SJoe Beteta name[inx] = '\0'; 4739f52228b8SJoe Beteta break; 4740f52228b8SJoe Beteta } 4741f52228b8SJoe Beteta if (name[inx] == '@') { 4742f52228b8SJoe Beteta break; 4743f52228b8SJoe Beteta } 4744f52228b8SJoe Beteta } 4745f52228b8SJoe Beteta 4746f52228b8SJoe Beteta skdev->pathname = kmem_zalloc(strlen(name) + 1, KM_SLEEP); 4747f52228b8SJoe Beteta (void) strlcpy(skdev->pathname, name, strlen(name) + 1); 4748f52228b8SJoe Beteta 4749f52228b8SJoe Beteta progress |= SKD_PATHNAME_ALLOCED; 4750f52228b8SJoe Beteta skdev->flags |= SKD_PATHNAME_ALLOCED; 4751f52228b8SJoe Beteta 4752f52228b8SJoe Beteta if (pci_config_setup(dip, &skdev->pci_handle) != DDI_SUCCESS) { 4753f52228b8SJoe Beteta cmn_err(CE_WARN, "!%s%d: pci_config_setup FAILED", 4754f52228b8SJoe Beteta DRV_NAME, instance); 4755f52228b8SJoe Beteta goto skd_attach_failed; 4756f52228b8SJoe Beteta } 4757f52228b8SJoe Beteta 4758f52228b8SJoe Beteta progress |= SKD_CONFIG_SPACE_SETUP; 4759f52228b8SJoe Beteta 4760f52228b8SJoe Beteta /* Save adapter path. */ 4761f52228b8SJoe Beteta 4762f52228b8SJoe Beteta (void) ddi_dev_nregs(dip, &nregs); 4763f52228b8SJoe Beteta 4764f52228b8SJoe Beteta /* 4765f52228b8SJoe Beteta * 0x0 Configuration Space 4766f52228b8SJoe Beteta * 0x1 I/O Space 4767f52228b8SJoe Beteta * 0x2 s1120 register space 4768f52228b8SJoe Beteta */ 4769f52228b8SJoe Beteta if (ddi_dev_regsize(dip, 1, ®size) != DDI_SUCCESS || 4770f52228b8SJoe Beteta ddi_regs_map_setup(dip, 1, &skdev->iobase, 0, regsize, 4771f52228b8SJoe Beteta &dev_acc_attr, &skdev->iobase_handle) != DDI_SUCCESS) { 4772f52228b8SJoe Beteta cmn_err(CE_WARN, "!%s%d: regs_map_setup(mem) failed", 4773f52228b8SJoe Beteta DRV_NAME, instance); 4774f52228b8SJoe Beteta goto skd_attach_failed; 4775f52228b8SJoe Beteta } 4776f52228b8SJoe Beteta progress |= SKD_REGS_MAPPED; 4777f52228b8SJoe Beteta 4778f52228b8SJoe Beteta skdev->iomap_iobase = skdev->iobase; 4779f52228b8SJoe Beteta skdev->iomap_handle = skdev->iobase_handle; 4780f52228b8SJoe Beteta 4781f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "%s: PCI iobase=%ph, iomap=%ph, regnum=%d, " 4782f52228b8SJoe Beteta "regsize=%ld", skdev->name, (void *)skdev->iobase, 4783f52228b8SJoe Beteta (void *)skdev->iomap_iobase, 1, regsize); 4784f52228b8SJoe Beteta 4785f52228b8SJoe Beteta if (ddi_dev_regsize(dip, 2, ®size) != DDI_SUCCESS || 4786f52228b8SJoe Beteta ddi_regs_map_setup(dip, 2, &skdev->dev_iobase, 0, regsize, 4787f52228b8SJoe Beteta &dev_acc_attr, &skdev->dev_handle) != DDI_SUCCESS) { 4788f52228b8SJoe Beteta cmn_err(CE_WARN, "!%s%d: regs_map_setup(mem) failed", 4789f52228b8SJoe Beteta DRV_NAME, instance); 4790f52228b8SJoe Beteta 4791f52228b8SJoe Beteta goto skd_attach_failed; 4792f52228b8SJoe Beteta } 4793f52228b8SJoe Beteta 4794f52228b8SJoe Beteta skdev->dev_memsize = (int)regsize; 4795f52228b8SJoe Beteta 4796f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "%s: DEV iobase=%ph regsize=%d", 4797f52228b8SJoe Beteta skdev->name, (void *)skdev->dev_iobase, 4798f52228b8SJoe Beteta skdev->dev_memsize); 4799f52228b8SJoe Beteta 4800f52228b8SJoe Beteta progress |= SKD_DEV_IOBASE_MAPPED; 4801f52228b8SJoe Beteta 4802f52228b8SJoe Beteta cmd_reg = pci_config_get16(skdev->pci_handle, PCI_CONF_COMM); 4803f52228b8SJoe Beteta cmd_reg |= (PCI_COMM_ME | PCI_COMM_INTX_DISABLE); 4804f52228b8SJoe Beteta cmd_reg &= ~PCI_COMM_PARITY_DETECT; 4805f52228b8SJoe Beteta pci_config_put16(skdev->pci_handle, PCI_CONF_COMM, cmd_reg); 4806f52228b8SJoe Beteta 4807f52228b8SJoe Beteta /* Get adapter PCI device information. */ 4808f52228b8SJoe Beteta skdev->vendor_id = pci_config_get16(skdev->pci_handle, PCI_CONF_VENID); 4809f52228b8SJoe Beteta skdev->device_id = pci_config_get16(skdev->pci_handle, PCI_CONF_DEVID); 4810f52228b8SJoe Beteta 4811f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "%s: %x-%x card detected", 4812f52228b8SJoe Beteta skdev->name, skdev->vendor_id, skdev->device_id); 4813f52228b8SJoe Beteta 4814f52228b8SJoe Beteta skd_get_properties(dip, skdev); 4815f52228b8SJoe Beteta 4816f52228b8SJoe Beteta (void) skd_init(skdev); 4817f52228b8SJoe Beteta 4818f52228b8SJoe Beteta if (skd_construct(skdev, instance)) { 4819f52228b8SJoe Beteta cmn_err(CE_WARN, "!%s: construct FAILED", skdev->name); 4820f52228b8SJoe Beteta goto skd_attach_failed; 4821f52228b8SJoe Beteta } 4822f52228b8SJoe Beteta 4823f52228b8SJoe Beteta progress |= SKD_PROBED; 4824f52228b8SJoe Beteta progress |= SKD_CONSTRUCTED; 4825f52228b8SJoe Beteta 4826f52228b8SJoe Beteta SIMPLEQ_INIT(&skdev->waitqueue); 4827f52228b8SJoe Beteta 4828f52228b8SJoe Beteta /* 4829f52228b8SJoe Beteta * Setup interrupt handler 4830f52228b8SJoe Beteta */ 4831f52228b8SJoe Beteta if (skd_setup_interrupts(skdev) != DDI_SUCCESS) { 4832f52228b8SJoe Beteta cmn_err(CE_WARN, "!%s: Unable to add interrupt", 4833f52228b8SJoe Beteta skdev->name); 4834f52228b8SJoe Beteta goto skd_attach_failed; 4835f52228b8SJoe Beteta } 4836f52228b8SJoe Beteta 4837f52228b8SJoe Beteta progress |= SKD_INTR_ADDED; 4838f52228b8SJoe Beteta 4839f52228b8SJoe Beteta ADAPTER_STATE_LOCK(skdev); 4840f52228b8SJoe Beteta skdev->flags |= SKD_ATTACHED; 4841f52228b8SJoe Beteta ADAPTER_STATE_UNLOCK(skdev); 4842f52228b8SJoe Beteta 4843f52228b8SJoe Beteta skdev->d_blkshift = 9; 4844f52228b8SJoe Beteta progress |= SKD_ATTACHED; 4845f52228b8SJoe Beteta 4846f52228b8SJoe Beteta 4847f52228b8SJoe Beteta skd_start_device(skdev); 4848f52228b8SJoe Beteta 4849f52228b8SJoe Beteta ADAPTER_STATE_LOCK(skdev); 4850f52228b8SJoe Beteta skdev->progress = progress; 4851f52228b8SJoe Beteta ADAPTER_STATE_UNLOCK(skdev); 4852f52228b8SJoe Beteta 4853f52228b8SJoe Beteta /* 4854f52228b8SJoe Beteta * Give the board a chance to 4855f52228b8SJoe Beteta * complete its initialization. 4856f52228b8SJoe Beteta */ 4857f52228b8SJoe Beteta if (skdev->gendisk_on != 1) 4858f52228b8SJoe Beteta (void) skd_wait_for_s1120(skdev); 4859f52228b8SJoe Beteta 4860f52228b8SJoe Beteta if (skdev->gendisk_on != 1) { 4861f52228b8SJoe Beteta cmn_err(CE_WARN, "!%s: s1120 failed to come ONLINE", 4862f52228b8SJoe Beteta skdev->name); 4863f52228b8SJoe Beteta goto skd_attach_failed; 4864f52228b8SJoe Beteta } 4865f52228b8SJoe Beteta 4866f52228b8SJoe Beteta ddi_report_dev(dip); 4867f52228b8SJoe Beteta 4868f52228b8SJoe Beteta skd_send_internal_skspcl(skdev, &skdev->internal_skspcl, INQUIRY); 4869f52228b8SJoe Beteta 4870f52228b8SJoe Beteta skdev->disks_initialized++; 4871f52228b8SJoe Beteta 4872f52228b8SJoe Beteta (void) strcpy(fw_version, "???"); 4873f52228b8SJoe Beteta (void) skd_pci_info(skdev, pci_str, sizeof (pci_str)); 4874f52228b8SJoe Beteta Dcmn_err(CE_NOTE, " sTec S1120 Driver(%s) version %s-b%s", 4875f52228b8SJoe Beteta DRV_NAME, DRV_VERSION, DRV_BUILD_ID); 4876f52228b8SJoe Beteta 4877f52228b8SJoe Beteta Dcmn_err(CE_NOTE, " sTec S1120 %04x:%04x %s 64 bit", 4878f52228b8SJoe Beteta skdev->vendor_id, skdev->device_id, pci_str); 4879f52228b8SJoe Beteta 4880f52228b8SJoe Beteta Dcmn_err(CE_NOTE, " sTec S1120 %s\n", skdev->pathname); 4881f52228b8SJoe Beteta 4882f52228b8SJoe Beteta if (*skdev->inq_serial_num) 4883f52228b8SJoe Beteta Dcmn_err(CE_NOTE, " sTec S1120 serial#=%s", 4884f52228b8SJoe Beteta skdev->inq_serial_num); 4885f52228b8SJoe Beteta 4886f52228b8SJoe Beteta if (*skdev->inq_product_id && 4887f52228b8SJoe Beteta *skdev->inq_product_rev) 4888f52228b8SJoe Beteta Dcmn_err(CE_NOTE, " sTec S1120 prod ID=%s prod rev=%s", 4889f52228b8SJoe Beteta skdev->inq_product_id, skdev->inq_product_rev); 4890f52228b8SJoe Beteta 4891f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "%s: intr-type-cap: %d", 4892f52228b8SJoe Beteta skdev->name, skdev->irq_type); 4893f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "%s: max-scsi-reqs: %d", 4894f52228b8SJoe Beteta skdev->name, skd_max_queue_depth); 4895f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "%s: max-sgs-per-req: %d", 4896f52228b8SJoe Beteta skdev->name, skd_sgs_per_request); 4897f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "%s: max-scsi-req-per-msg: %d", 4898f52228b8SJoe Beteta skdev->name, skd_max_req_per_msg); 4899f52228b8SJoe Beteta 4900f52228b8SJoe Beteta if (skd_bd_attach(dip, skdev) == DDI_FAILURE) 4901f52228b8SJoe Beteta goto skd_attach_failed; 4902f52228b8SJoe Beteta 4903f52228b8SJoe Beteta skd_update_props(skdev, dip); 4904f52228b8SJoe Beteta 4905f52228b8SJoe Beteta /* Enable timer */ 4906f52228b8SJoe Beteta skd_start_timer(skdev); 4907f52228b8SJoe Beteta 4908f52228b8SJoe Beteta ADAPTER_STATE_LOCK(skdev); 4909f52228b8SJoe Beteta skdev->progress = progress; 4910f52228b8SJoe Beteta ADAPTER_STATE_UNLOCK(skdev); 4911f52228b8SJoe Beteta 4912f52228b8SJoe Beteta skdev->attached = 1; 4913f52228b8SJoe Beteta return (DDI_SUCCESS); 4914f52228b8SJoe Beteta 4915f52228b8SJoe Beteta skd_attach_failed: 4916f52228b8SJoe Beteta skd_dealloc_resources(dip, skdev, progress, instance); 4917f52228b8SJoe Beteta 4918f52228b8SJoe Beteta if ((skdev->flags & SKD_MUTEX_DESTROYED) == 0) { 4919f52228b8SJoe Beteta skd_destroy_mutex(skdev); 4920f52228b8SJoe Beteta } 4921f52228b8SJoe Beteta 4922f52228b8SJoe Beteta ddi_soft_state_free(skd_state, instance); 4923f52228b8SJoe Beteta 4924f52228b8SJoe Beteta cmn_err(CE_WARN, "!skd_attach FAILED: progress=%x", progress); 4925f52228b8SJoe Beteta return (DDI_FAILURE); 4926f52228b8SJoe Beteta } 4927f52228b8SJoe Beteta 4928f52228b8SJoe Beteta /* 4929f52228b8SJoe Beteta * 4930f52228b8SJoe Beteta * Name: skd_halt 4931f52228b8SJoe Beteta * 4932f52228b8SJoe Beteta * Inputs: skdev - device state structure. 4933f52228b8SJoe Beteta * 4934f52228b8SJoe Beteta * Returns: Nothing. 4935f52228b8SJoe Beteta * 4936f52228b8SJoe Beteta */ 4937f52228b8SJoe Beteta static void 4938f52228b8SJoe Beteta skd_halt(skd_device_t *skdev) 4939f52228b8SJoe Beteta { 4940f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "%s: halt/suspend ......", skdev->name); 4941f52228b8SJoe Beteta } 4942f52228b8SJoe Beteta 4943f52228b8SJoe Beteta /* 4944f52228b8SJoe Beteta * 4945f52228b8SJoe Beteta * Name: skd_detach, detaches driver from the system. 4946f52228b8SJoe Beteta * 4947f52228b8SJoe Beteta * Inputs: dip - device info structure. 4948f52228b8SJoe Beteta * 4949f52228b8SJoe Beteta * Returns: DDI_SUCCESS on successful detach otherwise DDI_FAILURE. 4950f52228b8SJoe Beteta * 4951f52228b8SJoe Beteta */ 4952f52228b8SJoe Beteta static int 4953f52228b8SJoe Beteta skd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 4954f52228b8SJoe Beteta { 4955f52228b8SJoe Beteta skd_buf_private_t *pbuf; 4956f52228b8SJoe Beteta skd_device_t *skdev; 4957f52228b8SJoe Beteta int instance; 4958f52228b8SJoe Beteta timeout_id_t timer_id = NULL; 4959f52228b8SJoe Beteta int rv1 = DDI_SUCCESS; 4960f52228b8SJoe Beteta struct skd_special_context *skspcl; 4961f52228b8SJoe Beteta 4962f52228b8SJoe Beteta instance = ddi_get_instance(dip); 4963f52228b8SJoe Beteta 4964f52228b8SJoe Beteta skdev = ddi_get_soft_state(skd_state, instance); 4965f52228b8SJoe Beteta if (skdev == NULL) { 4966f52228b8SJoe Beteta cmn_err(CE_WARN, "!detach failed: NULL skd state"); 4967f52228b8SJoe Beteta 4968f52228b8SJoe Beteta return (DDI_FAILURE); 4969f52228b8SJoe Beteta } 4970f52228b8SJoe Beteta 4971f52228b8SJoe Beteta Dcmn_err(CE_CONT, "skd_detach(%d): entered", instance); 4972f52228b8SJoe Beteta 4973f52228b8SJoe Beteta switch (cmd) { 4974f52228b8SJoe Beteta case DDI_DETACH: 4975f52228b8SJoe Beteta /* Test for packet cache inuse. */ 4976f52228b8SJoe Beteta ADAPTER_STATE_LOCK(skdev); 4977f52228b8SJoe Beteta 4978f52228b8SJoe Beteta /* Stop command/event processing. */ 4979f52228b8SJoe Beteta skdev->flags |= (SKD_SUSPENDED | SKD_CMD_ABORT_TMO); 4980f52228b8SJoe Beteta 4981f52228b8SJoe Beteta /* Disable driver timer if no adapters. */ 4982f52228b8SJoe Beteta if (skdev->skd_timer_timeout_id != 0) { 4983f52228b8SJoe Beteta timer_id = skdev->skd_timer_timeout_id; 4984f52228b8SJoe Beteta skdev->skd_timer_timeout_id = 0; 4985f52228b8SJoe Beteta } 4986f52228b8SJoe Beteta ADAPTER_STATE_UNLOCK(skdev); 4987f52228b8SJoe Beteta 4988f52228b8SJoe Beteta if (timer_id != 0) { 4989f52228b8SJoe Beteta (void) untimeout(timer_id); 4990f52228b8SJoe Beteta } 4991f52228b8SJoe Beteta 4992f52228b8SJoe Beteta #ifdef SKD_PM 4993f52228b8SJoe Beteta if (skdev->power_level != LOW_POWER_LEVEL) { 4994f52228b8SJoe Beteta skd_halt(skdev); 4995f52228b8SJoe Beteta skdev->power_level = LOW_POWER_LEVEL; 4996f52228b8SJoe Beteta } 4997f52228b8SJoe Beteta #endif 4998f52228b8SJoe Beteta skspcl = &skdev->internal_skspcl; 4999f52228b8SJoe Beteta skd_send_internal_skspcl(skdev, skspcl, SYNCHRONIZE_CACHE); 5000f52228b8SJoe Beteta 5001f52228b8SJoe Beteta skd_stop_device(skdev); 5002f52228b8SJoe Beteta 5003f52228b8SJoe Beteta /* 5004f52228b8SJoe Beteta * Clear request queue. 5005f52228b8SJoe Beteta */ 5006f52228b8SJoe Beteta while (!SIMPLEQ_EMPTY(&skdev->waitqueue)) { 5007f52228b8SJoe Beteta pbuf = skd_get_queued_pbuf(skdev); 5008f52228b8SJoe Beteta skd_end_request_abnormal(skdev, pbuf, ECANCELED, 5009f52228b8SJoe Beteta SKD_IODONE_WNIOC); 5010f52228b8SJoe Beteta Dcmn_err(CE_NOTE, 5011f52228b8SJoe Beteta "detach: cancelled pbuf %p %ld <%s> %lld\n", 5012f52228b8SJoe Beteta (void *)pbuf, pbuf->x_xfer->x_nblks, 5013f52228b8SJoe Beteta (pbuf->dir & B_READ) ? "Read" : "Write", 5014f52228b8SJoe Beteta pbuf->x_xfer->x_blkno); 5015f52228b8SJoe Beteta } 5016f52228b8SJoe Beteta 5017f52228b8SJoe Beteta skd_bd_detach(skdev); 5018f52228b8SJoe Beteta 5019f52228b8SJoe Beteta skd_dealloc_resources(dip, skdev, skdev->progress, instance); 5020f52228b8SJoe Beteta 5021f52228b8SJoe Beteta if ((skdev->flags & SKD_MUTEX_DESTROYED) == 0) { 5022f52228b8SJoe Beteta skd_destroy_mutex(skdev); 5023f52228b8SJoe Beteta } 5024f52228b8SJoe Beteta 5025f52228b8SJoe Beteta ddi_soft_state_free(skd_state, instance); 5026f52228b8SJoe Beteta 5027f52228b8SJoe Beteta skd_exit(); 5028f52228b8SJoe Beteta 5029f52228b8SJoe Beteta break; 5030f52228b8SJoe Beteta 5031f52228b8SJoe Beteta case DDI_SUSPEND: 5032f52228b8SJoe Beteta /* Block timer. */ 5033f52228b8SJoe Beteta 5034f52228b8SJoe Beteta ADAPTER_STATE_LOCK(skdev); 5035f52228b8SJoe Beteta skdev->flags |= SKD_SUSPENDED; 5036f52228b8SJoe Beteta 5037f52228b8SJoe Beteta /* Disable driver timer if last adapter. */ 5038f52228b8SJoe Beteta if (skdev->skd_timer_timeout_id != 0) { 5039f52228b8SJoe Beteta timer_id = skdev->skd_timer_timeout_id; 5040f52228b8SJoe Beteta skdev->skd_timer_timeout_id = 0; 5041f52228b8SJoe Beteta } 5042f52228b8SJoe Beteta ADAPTER_STATE_UNLOCK(skdev); 5043f52228b8SJoe Beteta 5044f52228b8SJoe Beteta if (timer_id != 0) { 5045f52228b8SJoe Beteta (void) untimeout(timer_id); 5046f52228b8SJoe Beteta } 5047f52228b8SJoe Beteta 5048f52228b8SJoe Beteta ddi_prop_remove_all(dip); 5049f52228b8SJoe Beteta 5050f52228b8SJoe Beteta skd_halt(skdev); 5051f52228b8SJoe Beteta 5052f52228b8SJoe Beteta break; 5053f52228b8SJoe Beteta default: 5054f52228b8SJoe Beteta rv1 = DDI_FAILURE; 5055f52228b8SJoe Beteta break; 5056f52228b8SJoe Beteta } 5057f52228b8SJoe Beteta 5058f52228b8SJoe Beteta if (rv1 != DDI_SUCCESS) { 5059f52228b8SJoe Beteta cmn_err(CE_WARN, "!skd_detach, failed, rv1=%x", rv1); 5060f52228b8SJoe Beteta } else { 5061f52228b8SJoe Beteta Dcmn_err(CE_CONT, "skd_detach: exiting"); 5062f52228b8SJoe Beteta } 5063f52228b8SJoe Beteta 5064f52228b8SJoe Beteta if (rv1 != DDI_SUCCESS) 5065f52228b8SJoe Beteta return (DDI_FAILURE); 5066f52228b8SJoe Beteta 5067f52228b8SJoe Beteta return (rv1); 5068f52228b8SJoe Beteta } 5069f52228b8SJoe Beteta 5070f52228b8SJoe Beteta /* 5071f52228b8SJoe Beteta * 5072f52228b8SJoe Beteta * Name: skd_devid_init, calls skd_setup_devid to setup 5073f52228b8SJoe Beteta * the device's devid structure. 5074f52228b8SJoe Beteta * 5075f52228b8SJoe Beteta * Inputs: arg - device state structure. 5076f52228b8SJoe Beteta * dip - dev_info structure. 5077f52228b8SJoe Beteta * devid - devid structure. 5078f52228b8SJoe Beteta * 5079f52228b8SJoe Beteta * Returns: Nothing. 5080f52228b8SJoe Beteta * 5081f52228b8SJoe Beteta */ 5082f52228b8SJoe Beteta /* ARGSUSED */ /* Upstream common source with other platforms. */ 5083f52228b8SJoe Beteta static int 5084f52228b8SJoe Beteta skd_devid_init(void *arg, dev_info_t *dip, ddi_devid_t *devid) 5085f52228b8SJoe Beteta { 5086f52228b8SJoe Beteta skd_device_t *skdev = arg; 5087f52228b8SJoe Beteta 5088f52228b8SJoe Beteta (void) skd_setup_devid(skdev, devid); 5089f52228b8SJoe Beteta 5090f52228b8SJoe Beteta return (0); 5091f52228b8SJoe Beteta } 5092f52228b8SJoe Beteta 5093f52228b8SJoe Beteta /* 5094f52228b8SJoe Beteta * 5095f52228b8SJoe Beteta * Name: skd_bd_driveinfo, retrieves device's info. 5096f52228b8SJoe Beteta * 5097f52228b8SJoe Beteta * Inputs: drive - drive data structure. 5098f52228b8SJoe Beteta * arg - device state structure. 5099f52228b8SJoe Beteta * 5100f52228b8SJoe Beteta * Returns: Nothing. 5101f52228b8SJoe Beteta * 5102f52228b8SJoe Beteta */ 5103f52228b8SJoe Beteta static void 5104f52228b8SJoe Beteta skd_bd_driveinfo(void *arg, bd_drive_t *drive) 5105f52228b8SJoe Beteta { 5106f52228b8SJoe Beteta skd_device_t *skdev = arg; 5107f52228b8SJoe Beteta 5108f52228b8SJoe Beteta drive->d_qsize = (skdev->queue_depth_limit * 4) / 5; 5109f52228b8SJoe Beteta drive->d_maxxfer = SKD_DMA_MAXXFER; 5110f52228b8SJoe Beteta drive->d_removable = B_FALSE; 5111f52228b8SJoe Beteta drive->d_hotpluggable = B_FALSE; 5112f52228b8SJoe Beteta drive->d_target = 0; 5113f52228b8SJoe Beteta drive->d_lun = 0; 5114510a6847SHans Rosenfeld 5115510a6847SHans Rosenfeld if (skdev->inquiry_is_valid != 0) { 5116510a6847SHans Rosenfeld drive->d_vendor = skdev->inq_vendor_id; 5117510a6847SHans Rosenfeld drive->d_vendor_len = strlen(drive->d_vendor); 5118510a6847SHans Rosenfeld 5119510a6847SHans Rosenfeld drive->d_product = skdev->inq_product_id; 5120510a6847SHans Rosenfeld drive->d_product_len = strlen(drive->d_product); 5121510a6847SHans Rosenfeld 5122510a6847SHans Rosenfeld drive->d_serial = skdev->inq_serial_num; 5123510a6847SHans Rosenfeld drive->d_serial_len = strlen(drive->d_serial); 5124510a6847SHans Rosenfeld 5125510a6847SHans Rosenfeld drive->d_revision = skdev->inq_product_rev; 5126510a6847SHans Rosenfeld drive->d_revision_len = strlen(drive->d_revision); 5127510a6847SHans Rosenfeld } 5128f52228b8SJoe Beteta } 5129f52228b8SJoe Beteta 5130f52228b8SJoe Beteta /* 5131f52228b8SJoe Beteta * 5132f52228b8SJoe Beteta * Name: skd_bd_mediainfo, retrieves device media info. 5133f52228b8SJoe Beteta * 5134f52228b8SJoe Beteta * Inputs: arg - device state structure. 5135f52228b8SJoe Beteta * media - container for media info. 5136f52228b8SJoe Beteta * 5137f52228b8SJoe Beteta * Returns: Zero. 5138f52228b8SJoe Beteta * 5139f52228b8SJoe Beteta */ 5140f52228b8SJoe Beteta static int 5141f52228b8SJoe Beteta skd_bd_mediainfo(void *arg, bd_media_t *media) 5142f52228b8SJoe Beteta { 5143f52228b8SJoe Beteta skd_device_t *skdev = arg; 5144f52228b8SJoe Beteta 5145f52228b8SJoe Beteta media->m_nblks = skdev->Nblocks; 5146f52228b8SJoe Beteta media->m_blksize = 512; 5147f52228b8SJoe Beteta media->m_pblksize = 4096; 5148f52228b8SJoe Beteta media->m_readonly = B_FALSE; 5149f52228b8SJoe Beteta media->m_solidstate = B_TRUE; 5150f52228b8SJoe Beteta 5151f52228b8SJoe Beteta return (0); 5152f52228b8SJoe Beteta } 5153f52228b8SJoe Beteta 5154f52228b8SJoe Beteta /* 5155f52228b8SJoe Beteta * 5156f52228b8SJoe Beteta * Name: skd_rw, performs R/W requests for blkdev driver. 5157f52228b8SJoe Beteta * 5158f52228b8SJoe Beteta * Inputs: skdev - device state structure. 5159f52228b8SJoe Beteta * xfer - tranfer structure. 5160f52228b8SJoe Beteta * dir - I/O direction. 5161f52228b8SJoe Beteta * 5162f52228b8SJoe Beteta * Returns: EAGAIN if device is not online. EIO if blkdev wants us to 5163f52228b8SJoe Beteta * be a dump device (for now). 5164f52228b8SJoe Beteta * Value returned by skd_start(). 5165f52228b8SJoe Beteta * 5166f52228b8SJoe Beteta */ 5167f52228b8SJoe Beteta static int 5168f52228b8SJoe Beteta skd_rw(skd_device_t *skdev, bd_xfer_t *xfer, int dir) 5169f52228b8SJoe Beteta { 5170f52228b8SJoe Beteta skd_buf_private_t *pbuf; 5171f52228b8SJoe Beteta 5172f52228b8SJoe Beteta /* 5173f52228b8SJoe Beteta * The x_flags structure element is not defined in Oracle Solaris 5174f52228b8SJoe Beteta */ 5175f52228b8SJoe Beteta /* We'll need to fix this in order to support dump on this device. */ 5176f52228b8SJoe Beteta if (xfer->x_flags & BD_XFER_POLL) 5177f52228b8SJoe Beteta return (EIO); 5178f52228b8SJoe Beteta 5179f52228b8SJoe Beteta if (skdev->state != SKD_DRVR_STATE_ONLINE) { 5180f52228b8SJoe Beteta Dcmn_err(CE_NOTE, "Device - not ONLINE"); 5181f52228b8SJoe Beteta 5182f52228b8SJoe Beteta skd_request_fn_not_online(skdev); 5183f52228b8SJoe Beteta 5184f52228b8SJoe Beteta return (EAGAIN); 5185f52228b8SJoe Beteta } 5186f52228b8SJoe Beteta 5187f52228b8SJoe Beteta pbuf = kmem_zalloc(sizeof (skd_buf_private_t), KM_NOSLEEP); 5188f52228b8SJoe Beteta if (pbuf == NULL) 5189f52228b8SJoe Beteta return (ENOMEM); 5190f52228b8SJoe Beteta 5191f52228b8SJoe Beteta WAITQ_LOCK(skdev); 5192f52228b8SJoe Beteta pbuf->dir = dir; 5193f52228b8SJoe Beteta pbuf->x_xfer = xfer; 5194f52228b8SJoe Beteta 5195f52228b8SJoe Beteta skd_queue(skdev, pbuf); 5196f52228b8SJoe Beteta skdev->ios_queued++; 5197f52228b8SJoe Beteta WAITQ_UNLOCK(skdev); 5198f52228b8SJoe Beteta 5199f52228b8SJoe Beteta skd_start(skdev); 5200f52228b8SJoe Beteta 5201f52228b8SJoe Beteta return (0); 5202f52228b8SJoe Beteta } 5203f52228b8SJoe Beteta 5204f52228b8SJoe Beteta /* 5205f52228b8SJoe Beteta * 5206f52228b8SJoe Beteta * Name: skd_bd_read, performs blkdev read requests. 5207f52228b8SJoe Beteta * 5208f52228b8SJoe Beteta * Inputs: arg - device state structure. 5209f52228b8SJoe Beteta * xfer - tranfer request structure. 5210f52228b8SJoe Beteta * 5211f52228b8SJoe Beteta * Returns: Value return by skd_rw(). 5212f52228b8SJoe Beteta * 5213f52228b8SJoe Beteta */ 5214f52228b8SJoe Beteta static int 5215f52228b8SJoe Beteta skd_bd_read(void *arg, bd_xfer_t *xfer) 5216f52228b8SJoe Beteta { 5217f52228b8SJoe Beteta return (skd_rw(arg, xfer, B_READ)); 5218f52228b8SJoe Beteta } 5219f52228b8SJoe Beteta 5220f52228b8SJoe Beteta /* 5221f52228b8SJoe Beteta * 5222f52228b8SJoe Beteta * Name: skd_bd_write, performs blkdev write requests. 5223f52228b8SJoe Beteta * 5224f52228b8SJoe Beteta * Inputs: arg - device state structure. 5225f52228b8SJoe Beteta * xfer - tranfer request structure. 5226f52228b8SJoe Beteta * 5227f52228b8SJoe Beteta * Returns: Value return by skd_rw(). 5228f52228b8SJoe Beteta * 5229f52228b8SJoe Beteta */ 5230f52228b8SJoe Beteta static int 5231f52228b8SJoe Beteta skd_bd_write(void *arg, bd_xfer_t *xfer) 5232f52228b8SJoe Beteta { 5233f52228b8SJoe Beteta return (skd_rw(arg, xfer, B_WRITE)); 5234f52228b8SJoe Beteta } 5235