1250199Sgrehan/*- 2250199Sgrehan * Copyright (c) 2009-2012 Microsoft Corp. 3250199Sgrehan * Copyright (c) 2012 NetApp Inc. 4250199Sgrehan * Copyright (c) 2012 Citrix Inc. 5250199Sgrehan * All rights reserved. 6250199Sgrehan * 7250199Sgrehan * Redistribution and use in source and binary forms, with or without 8250199Sgrehan * modification, are permitted provided that the following conditions 9250199Sgrehan * are met: 10250199Sgrehan * 1. Redistributions of source code must retain the above copyright 11250199Sgrehan * notice unmodified, this list of conditions, and the following 12250199Sgrehan * disclaimer. 13250199Sgrehan * 2. Redistributions in binary form must reproduce the above copyright 14250199Sgrehan * notice, this list of conditions and the following disclaimer in the 15250199Sgrehan * documentation and/or other materials provided with the distribution. 16250199Sgrehan * 17250199Sgrehan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18250199Sgrehan * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19250199Sgrehan * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20250199Sgrehan * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21250199Sgrehan * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22250199Sgrehan * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23250199Sgrehan * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24250199Sgrehan * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25250199Sgrehan * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26250199Sgrehan * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27250199Sgrehan */ 28250199Sgrehan 29250199Sgrehan/** 30250199Sgrehan * StorVSC driver for Hyper-V. This driver presents a SCSI HBA interface 31250199Sgrehan * to the Comman Access Method (CAM) layer. CAM control blocks (CCBs) are 32250199Sgrehan * converted into VSCSI protocol messages which are delivered to the parent 33250199Sgrehan * partition StorVSP driver over the Hyper-V VMBUS. 34250199Sgrehan */ 35256276Sdim#include <sys/cdefs.h> 36256276Sdim__FBSDID("$FreeBSD: releng/10.2/sys/dev/hyperv/storvsc/hv_storvsc_drv_freebsd.c 283644 2015-05-28 09:20:35Z whu $"); 37250199Sgrehan 38250199Sgrehan#include <sys/param.h> 39250199Sgrehan#include <sys/proc.h> 40250199Sgrehan#include <sys/condvar.h> 41283280Swhu#include <sys/time.h> 42250199Sgrehan#include <sys/systm.h> 43250199Sgrehan#include <sys/sockio.h> 44250199Sgrehan#include <sys/mbuf.h> 45250199Sgrehan#include <sys/malloc.h> 46250199Sgrehan#include <sys/module.h> 47250199Sgrehan#include <sys/kernel.h> 48250199Sgrehan#include <sys/queue.h> 49250199Sgrehan#include <sys/lock.h> 50250199Sgrehan#include <sys/sx.h> 51250199Sgrehan#include <sys/taskqueue.h> 52250199Sgrehan#include <sys/bus.h> 53250199Sgrehan#include <sys/mutex.h> 54250199Sgrehan#include <sys/callout.h> 55250199Sgrehan#include <vm/vm.h> 56250199Sgrehan#include <vm/pmap.h> 57283280Swhu#include <vm/uma.h> 58250199Sgrehan#include <sys/lock.h> 59250199Sgrehan#include <sys/sema.h> 60283280Swhu#include <sys/sglist.h> 61283280Swhu#include <machine/bus.h> 62283280Swhu#include <sys/bus_dma.h> 63250199Sgrehan 64250199Sgrehan#include <cam/cam.h> 65250199Sgrehan#include <cam/cam_ccb.h> 66250199Sgrehan#include <cam/cam_periph.h> 67250199Sgrehan#include <cam/cam_sim.h> 68250199Sgrehan#include <cam/cam_xpt_sim.h> 69250199Sgrehan#include <cam/cam_xpt_internal.h> 70250199Sgrehan#include <cam/cam_debug.h> 71250199Sgrehan#include <cam/scsi/scsi_all.h> 72250199Sgrehan#include <cam/scsi/scsi_message.h> 73250199Sgrehan 74250199Sgrehan#include <dev/hyperv/include/hyperv.h> 75250199Sgrehan#include "hv_vstorage.h" 76250199Sgrehan 77250199Sgrehan#define STORVSC_RINGBUFFER_SIZE (20*PAGE_SIZE) 78250199Sgrehan#define STORVSC_MAX_LUNS_PER_TARGET (64) 79250199Sgrehan#define STORVSC_MAX_IO_REQUESTS (STORVSC_MAX_LUNS_PER_TARGET * 2) 80250199Sgrehan#define BLKVSC_MAX_IDE_DISKS_PER_TARGET (1) 81250199Sgrehan#define BLKVSC_MAX_IO_REQUESTS STORVSC_MAX_IO_REQUESTS 82273429Sgjb#define STORVSC_MAX_TARGETS (2) 83250199Sgrehan 84283280Swhu#define STORVSC_WIN7_MAJOR 4 85283280Swhu#define STORVSC_WIN7_MINOR 2 86283280Swhu 87283280Swhu#define STORVSC_WIN8_MAJOR 5 88283280Swhu#define STORVSC_WIN8_MINOR 1 89283280Swhu 90283644Swhu#define VSTOR_PKT_SIZE (sizeof(struct vstor_packet) - vmscsi_size_delta) 91283644Swhu 92283280Swhu#define HV_ALIGN(x, a) roundup2(x, a) 93283280Swhu 94250199Sgrehanstruct storvsc_softc; 95250199Sgrehan 96283280Swhustruct hv_sgl_node { 97283280Swhu LIST_ENTRY(hv_sgl_node) link; 98283280Swhu struct sglist *sgl_data; 99283280Swhu}; 100283280Swhu 101283280Swhustruct hv_sgl_page_pool{ 102283280Swhu LIST_HEAD(, hv_sgl_node) in_use_sgl_list; 103283280Swhu LIST_HEAD(, hv_sgl_node) free_sgl_list; 104283280Swhu boolean_t is_init; 105283280Swhu} g_hv_sgl_page_pool; 106283280Swhu 107283280Swhu#define STORVSC_MAX_SG_PAGE_CNT STORVSC_MAX_IO_REQUESTS * HV_MAX_MULTIPAGE_BUFFER_COUNT 108283280Swhu 109250199Sgrehanenum storvsc_request_type { 110250199Sgrehan WRITE_TYPE, 111250199Sgrehan READ_TYPE, 112250199Sgrehan UNKNOWN_TYPE 113250199Sgrehan}; 114250199Sgrehan 115250199Sgrehanstruct hv_storvsc_request { 116250199Sgrehan LIST_ENTRY(hv_storvsc_request) link; 117250199Sgrehan struct vstor_packet vstor_packet; 118250199Sgrehan hv_vmbus_multipage_buffer data_buf; 119250199Sgrehan void *sense_data; 120250199Sgrehan uint8_t sense_info_len; 121250199Sgrehan uint8_t retries; 122250199Sgrehan union ccb *ccb; 123250199Sgrehan struct storvsc_softc *softc; 124250199Sgrehan struct callout callout; 125250199Sgrehan struct sema synch_sema; /*Synchronize the request/response if needed */ 126283280Swhu struct sglist *bounce_sgl; 127283280Swhu unsigned int bounce_sgl_count; 128283280Swhu uint64_t not_aligned_seg_bits; 129250199Sgrehan}; 130250199Sgrehan 131250199Sgrehanstruct storvsc_softc { 132250199Sgrehan struct hv_device *hs_dev; 133283280Swhu LIST_HEAD(, hv_storvsc_request) hs_free_list; 134283280Swhu struct mtx hs_lock; 135283280Swhu struct storvsc_driver_props *hs_drv_props; 136283280Swhu int hs_unit; 137283280Swhu uint32_t hs_frozen; 138283280Swhu struct cam_sim *hs_sim; 139283280Swhu struct cam_path *hs_path; 140250199Sgrehan uint32_t hs_num_out_reqs; 141250199Sgrehan boolean_t hs_destroy; 142250199Sgrehan boolean_t hs_drain_notify; 143283280Swhu boolean_t hs_open_multi_channel; 144250199Sgrehan struct sema hs_drain_sema; 145250199Sgrehan struct hv_storvsc_request hs_init_req; 146250199Sgrehan struct hv_storvsc_request hs_reset_req; 147250199Sgrehan}; 148250199Sgrehan 149250199Sgrehan 150250199Sgrehan/** 151250199Sgrehan * HyperV storvsc timeout testing cases: 152250199Sgrehan * a. IO returned after first timeout; 153250199Sgrehan * b. IO returned after second timeout and queue freeze; 154250199Sgrehan * c. IO returned while timer handler is running 155250199Sgrehan * The first can be tested by "sg_senddiag -vv /dev/daX", 156250199Sgrehan * and the second and third can be done by 157250199Sgrehan * "sg_wr_mode -v -p 08 -c 0,1a -m 0,ff /dev/daX". 158283280Swhu */ 159250199Sgrehan#define HVS_TIMEOUT_TEST 0 160250199Sgrehan 161250199Sgrehan/* 162250199Sgrehan * Bus/adapter reset functionality on the Hyper-V host is 163250199Sgrehan * buggy and it will be disabled until 164250199Sgrehan * it can be further tested. 165250199Sgrehan */ 166250199Sgrehan#define HVS_HOST_RESET 0 167250199Sgrehan 168250199Sgrehanstruct storvsc_driver_props { 169250199Sgrehan char *drv_name; 170250199Sgrehan char *drv_desc; 171250199Sgrehan uint8_t drv_max_luns_per_target; 172283280Swhu uint8_t drv_max_ios_per_target; 173250199Sgrehan uint32_t drv_ringbuffer_size; 174250199Sgrehan}; 175250199Sgrehan 176250199Sgrehanenum hv_storage_type { 177250199Sgrehan DRIVER_BLKVSC, 178250199Sgrehan DRIVER_STORVSC, 179250199Sgrehan DRIVER_UNKNOWN 180250199Sgrehan}; 181250199Sgrehan 182250199Sgrehan#define HS_MAX_ADAPTERS 10 183250199Sgrehan 184283280Swhu#define HV_STORAGE_SUPPORTS_MULTI_CHANNEL 0x1 185283280Swhu 186250199Sgrehan/* {ba6163d9-04a1-4d29-b605-72e2ffb1dc7f} */ 187250199Sgrehanstatic const hv_guid gStorVscDeviceType={ 188250199Sgrehan .data = {0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d, 189250199Sgrehan 0xb6, 0x05, 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f} 190250199Sgrehan}; 191250199Sgrehan 192250199Sgrehan/* {32412632-86cb-44a2-9b5c-50d1417354f5} */ 193250199Sgrehanstatic const hv_guid gBlkVscDeviceType={ 194250199Sgrehan .data = {0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44, 195250199Sgrehan 0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5} 196250199Sgrehan}; 197250199Sgrehan 198250199Sgrehanstatic struct storvsc_driver_props g_drv_props_table[] = { 199250199Sgrehan {"blkvsc", "Hyper-V IDE Storage Interface", 200250199Sgrehan BLKVSC_MAX_IDE_DISKS_PER_TARGET, BLKVSC_MAX_IO_REQUESTS, 201250199Sgrehan STORVSC_RINGBUFFER_SIZE}, 202250199Sgrehan {"storvsc", "Hyper-V SCSI Storage Interface", 203250199Sgrehan STORVSC_MAX_LUNS_PER_TARGET, STORVSC_MAX_IO_REQUESTS, 204250199Sgrehan STORVSC_RINGBUFFER_SIZE} 205250199Sgrehan}; 206250199Sgrehan 207283644Swhu/* 208283644Swhu * Sense buffer size changed in win8; have a run-time 209283644Swhu * variable to track the size we should use. 210283644Swhu */ 211283644Swhustatic int sense_buffer_size; 212283644Swhu 213283644Swhu/* 214283644Swhu * The size of the vmscsi_request has changed in win8. The 215283644Swhu * additional size is for the newly added elements in the 216283644Swhu * structure. These elements are valid only when we are talking 217283644Swhu * to a win8 host. 218283644Swhu * Track the correct size we need to apply. 219283644Swhu */ 220283644Swhustatic int vmscsi_size_delta; 221283644Swhu 222283280Swhustatic int storvsc_current_major; 223283280Swhustatic int storvsc_current_minor; 224283280Swhu 225250199Sgrehan/* static functions */ 226250199Sgrehanstatic int storvsc_probe(device_t dev); 227250199Sgrehanstatic int storvsc_attach(device_t dev); 228250199Sgrehanstatic int storvsc_detach(device_t dev); 229250199Sgrehanstatic void storvsc_poll(struct cam_sim * sim); 230250199Sgrehanstatic void storvsc_action(struct cam_sim * sim, union ccb * ccb); 231283280Swhustatic int create_storvsc_request(union ccb *ccb, struct hv_storvsc_request *reqp); 232250199Sgrehanstatic void storvsc_free_request(struct storvsc_softc *sc, struct hv_storvsc_request *reqp); 233250199Sgrehanstatic enum hv_storage_type storvsc_get_storage_type(device_t dev); 234283644Swhustatic void hv_storvsc_rescan_target(struct storvsc_softc *sc); 235250199Sgrehanstatic void hv_storvsc_on_channel_callback(void *context); 236250199Sgrehanstatic void hv_storvsc_on_iocompletion( struct storvsc_softc *sc, 237250199Sgrehan struct vstor_packet *vstor_packet, 238250199Sgrehan struct hv_storvsc_request *request); 239250199Sgrehanstatic int hv_storvsc_connect_vsp(struct hv_device *device); 240250199Sgrehanstatic void storvsc_io_done(struct hv_storvsc_request *reqp); 241283280Swhustatic void storvsc_copy_sgl_to_bounce_buf(struct sglist *bounce_sgl, 242283280Swhu bus_dma_segment_t *orig_sgl, 243283280Swhu unsigned int orig_sgl_count, 244283280Swhu uint64_t seg_bits); 245283280Swhuvoid storvsc_copy_from_bounce_buf_to_sgl(bus_dma_segment_t *dest_sgl, 246283280Swhu unsigned int dest_sgl_count, 247283280Swhu struct sglist* src_sgl, 248283280Swhu uint64_t seg_bits); 249250199Sgrehan 250250199Sgrehanstatic device_method_t storvsc_methods[] = { 251250199Sgrehan /* Device interface */ 252250199Sgrehan DEVMETHOD(device_probe, storvsc_probe), 253250199Sgrehan DEVMETHOD(device_attach, storvsc_attach), 254250199Sgrehan DEVMETHOD(device_detach, storvsc_detach), 255250199Sgrehan DEVMETHOD(device_shutdown, bus_generic_shutdown), 256252645Sgrehan DEVMETHOD_END 257250199Sgrehan}; 258250199Sgrehan 259250199Sgrehanstatic driver_t storvsc_driver = { 260250199Sgrehan "storvsc", storvsc_methods, sizeof(struct storvsc_softc), 261250199Sgrehan}; 262250199Sgrehan 263250199Sgrehanstatic devclass_t storvsc_devclass; 264250199SgrehanDRIVER_MODULE(storvsc, vmbus, storvsc_driver, storvsc_devclass, 0, 0); 265252645SgrehanMODULE_VERSION(storvsc, 1); 266250199SgrehanMODULE_DEPEND(storvsc, vmbus, 1, 1, 1); 267250199Sgrehan 268250199Sgrehan 269250199Sgrehan/** 270283280Swhu * The host is capable of sending messages to us that are 271250199Sgrehan * completely unsolicited. So, we need to address the race 272250199Sgrehan * condition where we may be in the process of unloading the 273250199Sgrehan * driver when the host may send us an unsolicited message. 274250199Sgrehan * We address this issue by implementing a sequentially 275250199Sgrehan * consistent protocol: 276250199Sgrehan * 277250199Sgrehan * 1. Channel callback is invoked while holding the the channel lock 278250199Sgrehan * and an unloading driver will reset the channel callback under 279250199Sgrehan * the protection of this channel lock. 280250199Sgrehan * 281250199Sgrehan * 2. To ensure bounded wait time for unloading a driver, we don't 282250199Sgrehan * permit outgoing traffic once the device is marked as being 283250199Sgrehan * destroyed. 284250199Sgrehan * 285250199Sgrehan * 3. Once the device is marked as being destroyed, we only 286283280Swhu * permit incoming traffic to properly account for 287250199Sgrehan * packets already sent out. 288250199Sgrehan */ 289250199Sgrehanstatic inline struct storvsc_softc * 290250199Sgrehanget_stor_device(struct hv_device *device, 291250199Sgrehan boolean_t outbound) 292250199Sgrehan{ 293250199Sgrehan struct storvsc_softc *sc; 294250199Sgrehan 295250199Sgrehan sc = device_get_softc(device->device); 296250199Sgrehan if (sc == NULL) { 297250199Sgrehan return NULL; 298250199Sgrehan } 299250199Sgrehan 300250199Sgrehan if (outbound) { 301250199Sgrehan /* 302250199Sgrehan * Here we permit outgoing I/O only 303250199Sgrehan * if the device is not being destroyed. 304250199Sgrehan */ 305250199Sgrehan 306250199Sgrehan if (sc->hs_destroy) { 307250199Sgrehan sc = NULL; 308250199Sgrehan } 309250199Sgrehan } else { 310250199Sgrehan /* 311250199Sgrehan * inbound case; if being destroyed 312250199Sgrehan * only permit to account for 313250199Sgrehan * messages already sent out. 314250199Sgrehan */ 315250199Sgrehan if (sc->hs_destroy && (sc->hs_num_out_reqs == 0)) { 316250199Sgrehan sc = NULL; 317250199Sgrehan } 318250199Sgrehan } 319250199Sgrehan return sc; 320250199Sgrehan} 321250199Sgrehan 322250199Sgrehan/** 323283280Swhu * @brief Callback handler, will be invoked when receive mutil-channel offer 324283280Swhu * 325283280Swhu * @param context new multi-channel 326283280Swhu */ 327283280Swhustatic void 328283280Swhustorvsc_handle_sc_creation(void *context) 329283280Swhu{ 330283280Swhu hv_vmbus_channel *new_channel; 331283280Swhu struct hv_device *device; 332283280Swhu struct storvsc_softc *sc; 333283280Swhu struct vmstor_chan_props props; 334283280Swhu int ret = 0; 335283280Swhu 336283280Swhu new_channel = (hv_vmbus_channel *)context; 337283280Swhu device = new_channel->primary_channel->device; 338283280Swhu sc = get_stor_device(device, TRUE); 339283280Swhu if (sc == NULL) 340283280Swhu return; 341283280Swhu 342283280Swhu if (FALSE == sc->hs_open_multi_channel) 343283280Swhu return; 344283280Swhu 345283280Swhu memset(&props, 0, sizeof(props)); 346283280Swhu 347283280Swhu ret = hv_vmbus_channel_open(new_channel, 348283280Swhu sc->hs_drv_props->drv_ringbuffer_size, 349283280Swhu sc->hs_drv_props->drv_ringbuffer_size, 350283280Swhu (void *)&props, 351283280Swhu sizeof(struct vmstor_chan_props), 352283280Swhu hv_storvsc_on_channel_callback, 353283280Swhu new_channel); 354283280Swhu 355283280Swhu return; 356283280Swhu} 357283280Swhu 358283280Swhu/** 359283280Swhu * @brief Send multi-channel creation request to host 360283280Swhu * 361283280Swhu * @param device a Hyper-V device pointer 362283280Swhu * @param max_chans the max channels supported by vmbus 363283280Swhu */ 364283280Swhustatic void 365283280Swhustorvsc_send_multichannel_request(struct hv_device *dev, int max_chans) 366283280Swhu{ 367283280Swhu struct storvsc_softc *sc; 368283280Swhu struct hv_storvsc_request *request; 369283280Swhu struct vstor_packet *vstor_packet; 370283280Swhu int request_channels_cnt = 0; 371283280Swhu int ret; 372283280Swhu 373283280Swhu /* get multichannels count that need to create */ 374283280Swhu request_channels_cnt = MIN(max_chans, mp_ncpus); 375283280Swhu 376283280Swhu sc = get_stor_device(dev, TRUE); 377283280Swhu if (sc == NULL) { 378283280Swhu printf("Storvsc_error: get sc failed while send mutilchannel " 379283280Swhu "request\n"); 380283280Swhu return; 381283280Swhu } 382283280Swhu 383283280Swhu request = &sc->hs_init_req; 384283280Swhu 385283280Swhu /* Establish a handler for multi-channel */ 386283280Swhu dev->channel->sc_creation_callback = storvsc_handle_sc_creation; 387283280Swhu 388283280Swhu /* request the host to create multi-channel */ 389283280Swhu memset(request, 0, sizeof(struct hv_storvsc_request)); 390283280Swhu 391283280Swhu sema_init(&request->synch_sema, 0, ("stor_synch_sema")); 392283280Swhu 393283280Swhu vstor_packet = &request->vstor_packet; 394283280Swhu 395283280Swhu vstor_packet->operation = VSTOR_OPERATION_CREATE_MULTI_CHANNELS; 396283280Swhu vstor_packet->flags = REQUEST_COMPLETION_FLAG; 397283280Swhu vstor_packet->u.multi_channels_cnt = request_channels_cnt; 398283280Swhu 399283280Swhu ret = hv_vmbus_channel_send_packet( 400283280Swhu dev->channel, 401283280Swhu vstor_packet, 402283644Swhu VSTOR_PKT_SIZE, 403283280Swhu (uint64_t)(uintptr_t)request, 404283280Swhu HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 405283280Swhu HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); 406283280Swhu 407283280Swhu /* wait for 5 seconds */ 408283280Swhu ret = sema_timedwait(&request->synch_sema, 5 * hz); 409283280Swhu if (ret != 0) { 410283280Swhu printf("Storvsc_error: create multi-channel timeout, %d\n", 411283280Swhu ret); 412283280Swhu return; 413283280Swhu } 414283280Swhu 415283280Swhu if (vstor_packet->operation != VSTOR_OPERATION_COMPLETEIO || 416283280Swhu vstor_packet->status != 0) { 417283280Swhu printf("Storvsc_error: create multi-channel invalid operation " 418283280Swhu "(%d) or statue (%u)\n", 419283280Swhu vstor_packet->operation, vstor_packet->status); 420283280Swhu return; 421283280Swhu } 422283280Swhu 423283280Swhu sc->hs_open_multi_channel = TRUE; 424283280Swhu 425283280Swhu if (bootverbose) 426283280Swhu printf("Storvsc create multi-channel success!\n"); 427283280Swhu} 428283280Swhu 429283280Swhu/** 430250199Sgrehan * @brief initialize channel connection to parent partition 431250199Sgrehan * 432250199Sgrehan * @param dev a Hyper-V device pointer 433250199Sgrehan * @returns 0 on success, non-zero error on failure 434250199Sgrehan */ 435250199Sgrehanstatic int 436250199Sgrehanhv_storvsc_channel_init(struct hv_device *dev) 437250199Sgrehan{ 438250199Sgrehan int ret = 0; 439250199Sgrehan struct hv_storvsc_request *request; 440250199Sgrehan struct vstor_packet *vstor_packet; 441250199Sgrehan struct storvsc_softc *sc; 442283280Swhu uint16_t max_chans = 0; 443283280Swhu boolean_t support_multichannel = FALSE; 444250199Sgrehan 445283280Swhu max_chans = 0; 446283280Swhu support_multichannel = FALSE; 447283280Swhu 448250199Sgrehan sc = get_stor_device(dev, TRUE); 449283280Swhu if (sc == NULL) 450283280Swhu return (ENODEV); 451250199Sgrehan 452250199Sgrehan request = &sc->hs_init_req; 453250199Sgrehan memset(request, 0, sizeof(struct hv_storvsc_request)); 454250199Sgrehan vstor_packet = &request->vstor_packet; 455250199Sgrehan request->softc = sc; 456250199Sgrehan 457250199Sgrehan /** 458250199Sgrehan * Initiate the vsc/vsp initialization protocol on the open channel 459250199Sgrehan */ 460250199Sgrehan sema_init(&request->synch_sema, 0, ("stor_synch_sema")); 461250199Sgrehan 462250199Sgrehan vstor_packet->operation = VSTOR_OPERATION_BEGININITIALIZATION; 463250199Sgrehan vstor_packet->flags = REQUEST_COMPLETION_FLAG; 464250199Sgrehan 465250199Sgrehan 466250199Sgrehan ret = hv_vmbus_channel_send_packet( 467250199Sgrehan dev->channel, 468250199Sgrehan vstor_packet, 469283644Swhu VSTOR_PKT_SIZE, 470266794Smarius (uint64_t)(uintptr_t)request, 471250199Sgrehan HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 472250199Sgrehan HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); 473250199Sgrehan 474283280Swhu if (ret != 0) 475250199Sgrehan goto cleanup; 476250199Sgrehan 477283280Swhu /* wait 5 seconds */ 478283280Swhu ret = sema_timedwait(&request->synch_sema, 5 * hz); 479283280Swhu if (ret != 0) 480250199Sgrehan goto cleanup; 481250199Sgrehan 482250199Sgrehan if (vstor_packet->operation != VSTOR_OPERATION_COMPLETEIO || 483250199Sgrehan vstor_packet->status != 0) { 484250199Sgrehan goto cleanup; 485250199Sgrehan } 486250199Sgrehan 487250199Sgrehan /* reuse the packet for version range supported */ 488250199Sgrehan 489250199Sgrehan memset(vstor_packet, 0, sizeof(struct vstor_packet)); 490250199Sgrehan vstor_packet->operation = VSTOR_OPERATION_QUERYPROTOCOLVERSION; 491250199Sgrehan vstor_packet->flags = REQUEST_COMPLETION_FLAG; 492250199Sgrehan 493283280Swhu vstor_packet->u.version.major_minor = 494283280Swhu VMSTOR_PROTOCOL_VERSION(storvsc_current_major, storvsc_current_minor); 495250199Sgrehan 496250199Sgrehan /* revision is only significant for Windows guests */ 497256276Sdim vstor_packet->u.version.revision = 0; 498250199Sgrehan 499250199Sgrehan ret = hv_vmbus_channel_send_packet( 500250199Sgrehan dev->channel, 501250199Sgrehan vstor_packet, 502283644Swhu VSTOR_PKT_SIZE, 503266794Smarius (uint64_t)(uintptr_t)request, 504250199Sgrehan HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 505250199Sgrehan HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); 506250199Sgrehan 507283280Swhu if (ret != 0) 508250199Sgrehan goto cleanup; 509250199Sgrehan 510283280Swhu /* wait 5 seconds */ 511283280Swhu ret = sema_timedwait(&request->synch_sema, 5 * hz); 512250199Sgrehan 513283280Swhu if (ret) 514250199Sgrehan goto cleanup; 515250199Sgrehan 516250199Sgrehan /* TODO: Check returned version */ 517250199Sgrehan if (vstor_packet->operation != VSTOR_OPERATION_COMPLETEIO || 518283280Swhu vstor_packet->status != 0) 519250199Sgrehan goto cleanup; 520250199Sgrehan 521250199Sgrehan /** 522250199Sgrehan * Query channel properties 523250199Sgrehan */ 524250199Sgrehan memset(vstor_packet, 0, sizeof(struct vstor_packet)); 525250199Sgrehan vstor_packet->operation = VSTOR_OPERATION_QUERYPROPERTIES; 526250199Sgrehan vstor_packet->flags = REQUEST_COMPLETION_FLAG; 527250199Sgrehan 528250199Sgrehan ret = hv_vmbus_channel_send_packet( 529250199Sgrehan dev->channel, 530250199Sgrehan vstor_packet, 531283644Swhu VSTOR_PKT_SIZE, 532266794Smarius (uint64_t)(uintptr_t)request, 533250199Sgrehan HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 534250199Sgrehan HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); 535250199Sgrehan 536283280Swhu if ( ret != 0) 537250199Sgrehan goto cleanup; 538250199Sgrehan 539283280Swhu /* wait 5 seconds */ 540283280Swhu ret = sema_timedwait(&request->synch_sema, 5 * hz); 541250199Sgrehan 542283280Swhu if (ret != 0) 543250199Sgrehan goto cleanup; 544250199Sgrehan 545250199Sgrehan /* TODO: Check returned version */ 546250199Sgrehan if (vstor_packet->operation != VSTOR_OPERATION_COMPLETEIO || 547283280Swhu vstor_packet->status != 0) { 548250199Sgrehan goto cleanup; 549250199Sgrehan } 550250199Sgrehan 551283280Swhu /* multi-channels feature is supported by WIN8 and above version */ 552283280Swhu max_chans = vstor_packet->u.chan_props.max_channel_cnt; 553283280Swhu if ((hv_vmbus_protocal_version != HV_VMBUS_VERSION_WIN7) && 554283280Swhu (hv_vmbus_protocal_version != HV_VMBUS_VERSION_WS2008) && 555283280Swhu (vstor_packet->u.chan_props.flags & 556283280Swhu HV_STORAGE_SUPPORTS_MULTI_CHANNEL)) { 557283280Swhu support_multichannel = TRUE; 558283280Swhu } 559283280Swhu 560250199Sgrehan memset(vstor_packet, 0, sizeof(struct vstor_packet)); 561250199Sgrehan vstor_packet->operation = VSTOR_OPERATION_ENDINITIALIZATION; 562250199Sgrehan vstor_packet->flags = REQUEST_COMPLETION_FLAG; 563250199Sgrehan 564250199Sgrehan ret = hv_vmbus_channel_send_packet( 565250199Sgrehan dev->channel, 566250199Sgrehan vstor_packet, 567283644Swhu VSTOR_PKT_SIZE, 568266794Smarius (uint64_t)(uintptr_t)request, 569250199Sgrehan HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 570250199Sgrehan HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); 571250199Sgrehan 572250199Sgrehan if (ret != 0) { 573250199Sgrehan goto cleanup; 574250199Sgrehan } 575250199Sgrehan 576283280Swhu /* wait 5 seconds */ 577283280Swhu ret = sema_timedwait(&request->synch_sema, 5 * hz); 578250199Sgrehan 579283280Swhu if (ret != 0) 580250199Sgrehan goto cleanup; 581250199Sgrehan 582250199Sgrehan if (vstor_packet->operation != VSTOR_OPERATION_COMPLETEIO || 583283280Swhu vstor_packet->status != 0) 584250199Sgrehan goto cleanup; 585250199Sgrehan 586283280Swhu /* 587283280Swhu * If multi-channel is supported, send multichannel create 588283280Swhu * request to host. 589283280Swhu */ 590283280Swhu if (support_multichannel) 591283280Swhu storvsc_send_multichannel_request(dev, max_chans); 592283280Swhu 593250199Sgrehancleanup: 594250199Sgrehan sema_destroy(&request->synch_sema); 595250199Sgrehan return (ret); 596250199Sgrehan} 597250199Sgrehan 598250199Sgrehan/** 599250199Sgrehan * @brief Open channel connection to paraent partition StorVSP driver 600250199Sgrehan * 601250199Sgrehan * Open and initialize channel connection to parent partition StorVSP driver. 602250199Sgrehan * 603250199Sgrehan * @param pointer to a Hyper-V device 604250199Sgrehan * @returns 0 on success, non-zero error on failure 605250199Sgrehan */ 606250199Sgrehanstatic int 607250199Sgrehanhv_storvsc_connect_vsp(struct hv_device *dev) 608250199Sgrehan{ 609250199Sgrehan int ret = 0; 610250199Sgrehan struct vmstor_chan_props props; 611250199Sgrehan struct storvsc_softc *sc; 612250199Sgrehan 613250199Sgrehan sc = device_get_softc(dev->device); 614250199Sgrehan 615250199Sgrehan memset(&props, 0, sizeof(struct vmstor_chan_props)); 616250199Sgrehan 617250199Sgrehan /* 618250199Sgrehan * Open the channel 619250199Sgrehan */ 620250199Sgrehan 621250199Sgrehan ret = hv_vmbus_channel_open( 622250199Sgrehan dev->channel, 623250199Sgrehan sc->hs_drv_props->drv_ringbuffer_size, 624250199Sgrehan sc->hs_drv_props->drv_ringbuffer_size, 625250199Sgrehan (void *)&props, 626250199Sgrehan sizeof(struct vmstor_chan_props), 627250199Sgrehan hv_storvsc_on_channel_callback, 628283280Swhu dev->channel); 629250199Sgrehan 630250199Sgrehan if (ret != 0) { 631250199Sgrehan return ret; 632250199Sgrehan } 633250199Sgrehan 634250199Sgrehan ret = hv_storvsc_channel_init(dev); 635250199Sgrehan 636250199Sgrehan return (ret); 637250199Sgrehan} 638250199Sgrehan 639250199Sgrehan#if HVS_HOST_RESET 640250199Sgrehanstatic int 641250199Sgrehanhv_storvsc_host_reset(struct hv_device *dev) 642250199Sgrehan{ 643250199Sgrehan int ret = 0; 644250199Sgrehan struct storvsc_softc *sc; 645250199Sgrehan 646250199Sgrehan struct hv_storvsc_request *request; 647250199Sgrehan struct vstor_packet *vstor_packet; 648250199Sgrehan 649250199Sgrehan sc = get_stor_device(dev, TRUE); 650250199Sgrehan if (sc == NULL) { 651250199Sgrehan return ENODEV; 652250199Sgrehan } 653250199Sgrehan 654250199Sgrehan request = &sc->hs_reset_req; 655250199Sgrehan request->softc = sc; 656250199Sgrehan vstor_packet = &request->vstor_packet; 657250199Sgrehan 658250199Sgrehan sema_init(&request->synch_sema, 0, "stor synch sema"); 659250199Sgrehan 660250199Sgrehan vstor_packet->operation = VSTOR_OPERATION_RESETBUS; 661250199Sgrehan vstor_packet->flags = REQUEST_COMPLETION_FLAG; 662250199Sgrehan 663250199Sgrehan ret = hv_vmbus_channel_send_packet(dev->channel, 664250199Sgrehan vstor_packet, 665283644Swhu VSTOR_PKT_SIZE, 666266794Smarius (uint64_t)(uintptr_t)&sc->hs_reset_req, 667250199Sgrehan HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 668250199Sgrehan HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); 669250199Sgrehan 670250199Sgrehan if (ret != 0) { 671250199Sgrehan goto cleanup; 672250199Sgrehan } 673250199Sgrehan 674283280Swhu ret = sema_timedwait(&request->synch_sema, 5 * hz); /* KYS 5 seconds */ 675250199Sgrehan 676250199Sgrehan if (ret) { 677250199Sgrehan goto cleanup; 678250199Sgrehan } 679250199Sgrehan 680250199Sgrehan 681250199Sgrehan /* 682283280Swhu * At this point, all outstanding requests in the adapter 683250199Sgrehan * should have been flushed out and return to us 684250199Sgrehan */ 685250199Sgrehan 686250199Sgrehancleanup: 687250199Sgrehan sema_destroy(&request->synch_sema); 688250199Sgrehan return (ret); 689250199Sgrehan} 690250199Sgrehan#endif /* HVS_HOST_RESET */ 691250199Sgrehan 692250199Sgrehan/** 693250199Sgrehan * @brief Function to initiate an I/O request 694250199Sgrehan * 695250199Sgrehan * @param device Hyper-V device pointer 696250199Sgrehan * @param request pointer to a request structure 697250199Sgrehan * @returns 0 on success, non-zero error on failure 698250199Sgrehan */ 699250199Sgrehanstatic int 700250199Sgrehanhv_storvsc_io_request(struct hv_device *device, 701250199Sgrehan struct hv_storvsc_request *request) 702250199Sgrehan{ 703250199Sgrehan struct storvsc_softc *sc; 704250199Sgrehan struct vstor_packet *vstor_packet = &request->vstor_packet; 705283280Swhu struct hv_vmbus_channel* outgoing_channel = NULL; 706250199Sgrehan int ret = 0; 707250199Sgrehan 708250199Sgrehan sc = get_stor_device(device, TRUE); 709250199Sgrehan 710250199Sgrehan if (sc == NULL) { 711250199Sgrehan return ENODEV; 712250199Sgrehan } 713250199Sgrehan 714250199Sgrehan vstor_packet->flags |= REQUEST_COMPLETION_FLAG; 715250199Sgrehan 716283644Swhu vstor_packet->u.vm_srb.length = VSTOR_PKT_SIZE; 717250199Sgrehan 718283644Swhu vstor_packet->u.vm_srb.sense_info_len = sense_buffer_size; 719250199Sgrehan 720256276Sdim vstor_packet->u.vm_srb.transfer_len = request->data_buf.length; 721250199Sgrehan 722250199Sgrehan vstor_packet->operation = VSTOR_OPERATION_EXECUTESRB; 723250199Sgrehan 724283280Swhu outgoing_channel = vmbus_select_outgoing_channel(device->channel); 725250199Sgrehan 726250199Sgrehan mtx_unlock(&request->softc->hs_lock); 727250199Sgrehan if (request->data_buf.length) { 728250199Sgrehan ret = hv_vmbus_channel_send_packet_multipagebuffer( 729283280Swhu outgoing_channel, 730250199Sgrehan &request->data_buf, 731283280Swhu vstor_packet, 732283644Swhu VSTOR_PKT_SIZE, 733266794Smarius (uint64_t)(uintptr_t)request); 734250199Sgrehan 735250199Sgrehan } else { 736250199Sgrehan ret = hv_vmbus_channel_send_packet( 737283280Swhu outgoing_channel, 738250199Sgrehan vstor_packet, 739283644Swhu VSTOR_PKT_SIZE, 740266794Smarius (uint64_t)(uintptr_t)request, 741250199Sgrehan HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 742250199Sgrehan HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); 743250199Sgrehan } 744250199Sgrehan mtx_lock(&request->softc->hs_lock); 745250199Sgrehan 746250199Sgrehan if (ret != 0) { 747250199Sgrehan printf("Unable to send packet %p ret %d", vstor_packet, ret); 748250199Sgrehan } else { 749250199Sgrehan atomic_add_int(&sc->hs_num_out_reqs, 1); 750250199Sgrehan } 751250199Sgrehan 752250199Sgrehan return (ret); 753250199Sgrehan} 754250199Sgrehan 755250199Sgrehan 756250199Sgrehan/** 757250199Sgrehan * Process IO_COMPLETION_OPERATION and ready 758250199Sgrehan * the result to be completed for upper layer 759250199Sgrehan * processing by the CAM layer. 760250199Sgrehan */ 761250199Sgrehanstatic void 762250199Sgrehanhv_storvsc_on_iocompletion(struct storvsc_softc *sc, 763250199Sgrehan struct vstor_packet *vstor_packet, 764250199Sgrehan struct hv_storvsc_request *request) 765250199Sgrehan{ 766250199Sgrehan struct vmscsi_req *vm_srb; 767250199Sgrehan 768256276Sdim vm_srb = &vstor_packet->u.vm_srb; 769250199Sgrehan 770250199Sgrehan if (((vm_srb->scsi_status & 0xFF) == SCSI_STATUS_CHECK_COND) && 771250199Sgrehan (vm_srb->srb_status & SRB_STATUS_AUTOSENSE_VALID)) { 772250199Sgrehan /* Autosense data available */ 773250199Sgrehan 774250199Sgrehan KASSERT(vm_srb->sense_info_len <= request->sense_info_len, 775250199Sgrehan ("vm_srb->sense_info_len <= " 776250199Sgrehan "request->sense_info_len")); 777250199Sgrehan 778256276Sdim memcpy(request->sense_data, vm_srb->u.sense_data, 779250199Sgrehan vm_srb->sense_info_len); 780250199Sgrehan 781250199Sgrehan request->sense_info_len = vm_srb->sense_info_len; 782250199Sgrehan } 783250199Sgrehan 784250199Sgrehan /* Complete request by passing to the CAM layer */ 785250199Sgrehan storvsc_io_done(request); 786250199Sgrehan atomic_subtract_int(&sc->hs_num_out_reqs, 1); 787250199Sgrehan if (sc->hs_drain_notify && (sc->hs_num_out_reqs == 0)) { 788250199Sgrehan sema_post(&sc->hs_drain_sema); 789250199Sgrehan } 790250199Sgrehan} 791250199Sgrehan 792250199Sgrehanstatic void 793283644Swhuhv_storvsc_rescan_target(struct storvsc_softc *sc) 794283644Swhu{ 795283644Swhu path_id_t pathid; 796283644Swhu target_id_t targetid; 797283644Swhu union ccb *ccb; 798283644Swhu 799283644Swhu pathid = cam_sim_path(sc->hs_sim); 800283644Swhu targetid = CAM_TARGET_WILDCARD; 801283644Swhu 802283644Swhu /* 803283644Swhu * Allocate a CCB and schedule a rescan. 804283644Swhu */ 805283644Swhu ccb = xpt_alloc_ccb_nowait(); 806283644Swhu if (ccb == NULL) { 807283644Swhu printf("unable to alloc CCB for rescan\n"); 808283644Swhu return; 809283644Swhu } 810283644Swhu 811283644Swhu if (xpt_create_path(&ccb->ccb_h.path, NULL, pathid, targetid, 812283644Swhu CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 813283644Swhu printf("unable to create path for rescan, pathid: %d," 814283644Swhu "targetid: %d\n", pathid, targetid); 815283644Swhu xpt_free_ccb(ccb); 816283644Swhu return; 817283644Swhu } 818283644Swhu 819283644Swhu if (targetid == CAM_TARGET_WILDCARD) 820283644Swhu ccb->ccb_h.func_code = XPT_SCAN_BUS; 821283644Swhu else 822283644Swhu ccb->ccb_h.func_code = XPT_SCAN_TGT; 823283644Swhu 824283644Swhu xpt_rescan(ccb); 825283644Swhu} 826283644Swhu 827283644Swhustatic void 828250199Sgrehanhv_storvsc_on_channel_callback(void *context) 829250199Sgrehan{ 830250199Sgrehan int ret = 0; 831283280Swhu hv_vmbus_channel *channel = (hv_vmbus_channel *)context; 832283280Swhu struct hv_device *device = NULL; 833250199Sgrehan struct storvsc_softc *sc; 834250199Sgrehan uint32_t bytes_recvd; 835250199Sgrehan uint64_t request_id; 836250199Sgrehan uint8_t packet[roundup2(sizeof(struct vstor_packet), 8)]; 837250199Sgrehan struct hv_storvsc_request *request; 838250199Sgrehan struct vstor_packet *vstor_packet; 839250199Sgrehan 840283280Swhu if (channel->primary_channel != NULL){ 841283280Swhu device = channel->primary_channel->device; 842283280Swhu } else { 843283280Swhu device = channel->device; 844283280Swhu } 845283280Swhu 846283280Swhu KASSERT(device, ("device is NULL")); 847283280Swhu 848250199Sgrehan sc = get_stor_device(device, FALSE); 849250199Sgrehan if (sc == NULL) { 850283280Swhu printf("Storvsc_error: get stor device failed.\n"); 851250199Sgrehan return; 852250199Sgrehan } 853250199Sgrehan 854250199Sgrehan ret = hv_vmbus_channel_recv_packet( 855283280Swhu channel, 856250199Sgrehan packet, 857283644Swhu roundup2(VSTOR_PKT_SIZE, 8), 858250199Sgrehan &bytes_recvd, 859250199Sgrehan &request_id); 860250199Sgrehan 861250199Sgrehan while ((ret == 0) && (bytes_recvd > 0)) { 862266794Smarius request = (struct hv_storvsc_request *)(uintptr_t)request_id; 863250199Sgrehan 864250199Sgrehan if ((request == &sc->hs_init_req) || 865250199Sgrehan (request == &sc->hs_reset_req)) { 866250199Sgrehan memcpy(&request->vstor_packet, packet, 867250199Sgrehan sizeof(struct vstor_packet)); 868283280Swhu sema_post(&request->synch_sema); 869250199Sgrehan } else { 870250199Sgrehan vstor_packet = (struct vstor_packet *)packet; 871250199Sgrehan switch(vstor_packet->operation) { 872250199Sgrehan case VSTOR_OPERATION_COMPLETEIO: 873283280Swhu if (request == NULL) 874283280Swhu panic("VMBUS: storvsc received a " 875283280Swhu "packet with NULL request id in " 876283280Swhu "COMPLETEIO operation."); 877283280Swhu 878250199Sgrehan hv_storvsc_on_iocompletion(sc, 879250199Sgrehan vstor_packet, request); 880250199Sgrehan break; 881250199Sgrehan case VSTOR_OPERATION_REMOVEDEVICE: 882283280Swhu printf("VMBUS: storvsc operation %d not " 883283280Swhu "implemented.\n", vstor_packet->operation); 884250199Sgrehan /* TODO: implement */ 885250199Sgrehan break; 886283644Swhu case VSTOR_OPERATION_ENUMERATE_BUS: 887283644Swhu hv_storvsc_rescan_target(sc); 888283644Swhu break; 889250199Sgrehan default: 890250199Sgrehan break; 891250199Sgrehan } 892250199Sgrehan } 893250199Sgrehan ret = hv_vmbus_channel_recv_packet( 894283280Swhu channel, 895250199Sgrehan packet, 896283644Swhu roundup2(VSTOR_PKT_SIZE, 8), 897250199Sgrehan &bytes_recvd, 898250199Sgrehan &request_id); 899250199Sgrehan } 900250199Sgrehan} 901250199Sgrehan 902250199Sgrehan/** 903250199Sgrehan * @brief StorVSC probe function 904250199Sgrehan * 905250199Sgrehan * Device probe function. Returns 0 if the input device is a StorVSC 906250199Sgrehan * device. Otherwise, a ENXIO is returned. If the input device is 907250199Sgrehan * for BlkVSC (paravirtual IDE) device and this support is disabled in 908250199Sgrehan * favor of the emulated ATA/IDE device, return ENXIO. 909250199Sgrehan * 910250199Sgrehan * @param a device 911250199Sgrehan * @returns 0 on success, ENXIO if not a matcing StorVSC device 912250199Sgrehan */ 913250199Sgrehanstatic int 914250199Sgrehanstorvsc_probe(device_t dev) 915250199Sgrehan{ 916252645Sgrehan int ata_disk_enable = 0; 917250199Sgrehan int ret = ENXIO; 918283280Swhu 919283644Swhu if (hv_vmbus_protocal_version == HV_VMBUS_VERSION_WS2008 || 920283644Swhu hv_vmbus_protocal_version == HV_VMBUS_VERSION_WIN7) { 921283644Swhu sense_buffer_size = PRE_WIN8_STORVSC_SENSE_BUFFER_SIZE; 922283644Swhu vmscsi_size_delta = sizeof(struct vmscsi_win8_extension); 923283644Swhu storvsc_current_major = STORVSC_WIN7_MAJOR; 924283644Swhu storvsc_current_minor = STORVSC_WIN7_MINOR; 925283644Swhu } else { 926283644Swhu sense_buffer_size = POST_WIN7_STORVSC_SENSE_BUFFER_SIZE; 927283644Swhu vmscsi_size_delta = 0; 928283280Swhu storvsc_current_major = STORVSC_WIN8_MAJOR; 929283280Swhu storvsc_current_minor = STORVSC_WIN8_MINOR; 930283280Swhu } 931283280Swhu 932250199Sgrehan switch (storvsc_get_storage_type(dev)) { 933250199Sgrehan case DRIVER_BLKVSC: 934252645Sgrehan if(bootverbose) 935252645Sgrehan device_printf(dev, "DRIVER_BLKVSC-Emulated ATA/IDE probe\n"); 936252645Sgrehan if (!getenv_int("hw.ata.disk_enable", &ata_disk_enable)) { 937252645Sgrehan if(bootverbose) 938252645Sgrehan device_printf(dev, 939252645Sgrehan "Enlightened ATA/IDE detected\n"); 940273580Sdelphij ret = BUS_PROBE_DEFAULT; 941252645Sgrehan } else if(bootverbose) 942252645Sgrehan device_printf(dev, "Emulated ATA/IDE set (hw.ata.disk_enable set)\n"); 943250199Sgrehan break; 944250199Sgrehan case DRIVER_STORVSC: 945252645Sgrehan if(bootverbose) 946252645Sgrehan device_printf(dev, "Enlightened SCSI device detected\n"); 947273580Sdelphij ret = BUS_PROBE_DEFAULT; 948250199Sgrehan break; 949250199Sgrehan default: 950250199Sgrehan ret = ENXIO; 951250199Sgrehan } 952250199Sgrehan return (ret); 953250199Sgrehan} 954250199Sgrehan 955250199Sgrehan/** 956250199Sgrehan * @brief StorVSC attach function 957250199Sgrehan * 958250199Sgrehan * Function responsible for allocating per-device structures, 959250199Sgrehan * setting up CAM interfaces and scanning for available LUNs to 960250199Sgrehan * be used for SCSI device peripherals. 961250199Sgrehan * 962250199Sgrehan * @param a device 963250199Sgrehan * @returns 0 on success or an error on failure 964250199Sgrehan */ 965250199Sgrehanstatic int 966250199Sgrehanstorvsc_attach(device_t dev) 967250199Sgrehan{ 968250199Sgrehan struct hv_device *hv_dev = vmbus_get_devctx(dev); 969250199Sgrehan enum hv_storage_type stor_type; 970250199Sgrehan struct storvsc_softc *sc; 971250199Sgrehan struct cam_devq *devq; 972283280Swhu int ret, i, j; 973250199Sgrehan struct hv_storvsc_request *reqp; 974250199Sgrehan struct root_hold_token *root_mount_token = NULL; 975283280Swhu struct hv_sgl_node *sgl_node = NULL; 976283280Swhu void *tmp_buff = NULL; 977250199Sgrehan 978250199Sgrehan /* 979250199Sgrehan * We need to serialize storvsc attach calls. 980250199Sgrehan */ 981250199Sgrehan root_mount_token = root_mount_hold("storvsc"); 982250199Sgrehan 983250199Sgrehan sc = device_get_softc(dev); 984250199Sgrehan if (sc == NULL) { 985250199Sgrehan ret = ENOMEM; 986250199Sgrehan goto cleanup; 987250199Sgrehan } 988250199Sgrehan 989250199Sgrehan stor_type = storvsc_get_storage_type(dev); 990250199Sgrehan 991250199Sgrehan if (stor_type == DRIVER_UNKNOWN) { 992250199Sgrehan ret = ENODEV; 993250199Sgrehan goto cleanup; 994250199Sgrehan } 995250199Sgrehan 996250199Sgrehan bzero(sc, sizeof(struct storvsc_softc)); 997250199Sgrehan 998250199Sgrehan /* fill in driver specific properties */ 999250199Sgrehan sc->hs_drv_props = &g_drv_props_table[stor_type]; 1000250199Sgrehan 1001250199Sgrehan /* fill in device specific properties */ 1002250199Sgrehan sc->hs_unit = device_get_unit(dev); 1003250199Sgrehan sc->hs_dev = hv_dev; 1004250199Sgrehan device_set_desc(dev, g_drv_props_table[stor_type].drv_desc); 1005250199Sgrehan 1006250199Sgrehan LIST_INIT(&sc->hs_free_list); 1007250199Sgrehan mtx_init(&sc->hs_lock, "hvslck", NULL, MTX_DEF); 1008250199Sgrehan 1009250199Sgrehan for (i = 0; i < sc->hs_drv_props->drv_max_ios_per_target; ++i) { 1010250199Sgrehan reqp = malloc(sizeof(struct hv_storvsc_request), 1011250199Sgrehan M_DEVBUF, M_WAITOK|M_ZERO); 1012250199Sgrehan reqp->softc = sc; 1013250199Sgrehan 1014250199Sgrehan LIST_INSERT_HEAD(&sc->hs_free_list, reqp, link); 1015250199Sgrehan } 1016250199Sgrehan 1017283280Swhu /* create sg-list page pool */ 1018283280Swhu if (FALSE == g_hv_sgl_page_pool.is_init) { 1019283280Swhu g_hv_sgl_page_pool.is_init = TRUE; 1020283280Swhu LIST_INIT(&g_hv_sgl_page_pool.in_use_sgl_list); 1021283280Swhu LIST_INIT(&g_hv_sgl_page_pool.free_sgl_list); 1022283280Swhu 1023283280Swhu /* 1024283280Swhu * Pre-create SG list, each SG list with 1025283280Swhu * HV_MAX_MULTIPAGE_BUFFER_COUNT segments, each 1026283280Swhu * segment has one page buffer 1027283280Swhu */ 1028283280Swhu for (i = 0; i < STORVSC_MAX_IO_REQUESTS; i++) { 1029283280Swhu sgl_node = malloc(sizeof(struct hv_sgl_node), 1030283280Swhu M_DEVBUF, M_WAITOK|M_ZERO); 1031283280Swhu 1032283280Swhu sgl_node->sgl_data = 1033283280Swhu sglist_alloc(HV_MAX_MULTIPAGE_BUFFER_COUNT, 1034283280Swhu M_WAITOK|M_ZERO); 1035283280Swhu 1036283280Swhu for (j = 0; j < HV_MAX_MULTIPAGE_BUFFER_COUNT; j++) { 1037283280Swhu tmp_buff = malloc(PAGE_SIZE, 1038283280Swhu M_DEVBUF, M_WAITOK|M_ZERO); 1039283280Swhu 1040283280Swhu sgl_node->sgl_data->sg_segs[j].ss_paddr = 1041283280Swhu (vm_paddr_t)tmp_buff; 1042283280Swhu } 1043283280Swhu 1044283280Swhu LIST_INSERT_HEAD(&g_hv_sgl_page_pool.free_sgl_list, 1045283280Swhu sgl_node, link); 1046283280Swhu } 1047283280Swhu } 1048283280Swhu 1049250199Sgrehan sc->hs_destroy = FALSE; 1050250199Sgrehan sc->hs_drain_notify = FALSE; 1051283280Swhu sc->hs_open_multi_channel = FALSE; 1052250199Sgrehan sema_init(&sc->hs_drain_sema, 0, "Store Drain Sema"); 1053250199Sgrehan 1054250199Sgrehan ret = hv_storvsc_connect_vsp(hv_dev); 1055250199Sgrehan if (ret != 0) { 1056250199Sgrehan goto cleanup; 1057250199Sgrehan } 1058250199Sgrehan 1059250199Sgrehan /* 1060250199Sgrehan * Create the device queue. 1061250199Sgrehan * Hyper-V maps each target to one SCSI HBA 1062250199Sgrehan */ 1063250199Sgrehan devq = cam_simq_alloc(sc->hs_drv_props->drv_max_ios_per_target); 1064250199Sgrehan if (devq == NULL) { 1065250199Sgrehan device_printf(dev, "Failed to alloc device queue\n"); 1066250199Sgrehan ret = ENOMEM; 1067250199Sgrehan goto cleanup; 1068250199Sgrehan } 1069250199Sgrehan 1070250199Sgrehan sc->hs_sim = cam_sim_alloc(storvsc_action, 1071250199Sgrehan storvsc_poll, 1072250199Sgrehan sc->hs_drv_props->drv_name, 1073250199Sgrehan sc, 1074250199Sgrehan sc->hs_unit, 1075250199Sgrehan &sc->hs_lock, 1, 1076250199Sgrehan sc->hs_drv_props->drv_max_ios_per_target, 1077250199Sgrehan devq); 1078250199Sgrehan 1079250199Sgrehan if (sc->hs_sim == NULL) { 1080250199Sgrehan device_printf(dev, "Failed to alloc sim\n"); 1081250199Sgrehan cam_simq_free(devq); 1082250199Sgrehan ret = ENOMEM; 1083250199Sgrehan goto cleanup; 1084250199Sgrehan } 1085250199Sgrehan 1086250199Sgrehan mtx_lock(&sc->hs_lock); 1087250199Sgrehan /* bus_id is set to 0, need to get it from VMBUS channel query? */ 1088250199Sgrehan if (xpt_bus_register(sc->hs_sim, dev, 0) != CAM_SUCCESS) { 1089250199Sgrehan cam_sim_free(sc->hs_sim, /*free_devq*/TRUE); 1090250199Sgrehan mtx_unlock(&sc->hs_lock); 1091250199Sgrehan device_printf(dev, "Unable to register SCSI bus\n"); 1092250199Sgrehan ret = ENXIO; 1093250199Sgrehan goto cleanup; 1094250199Sgrehan } 1095250199Sgrehan 1096250199Sgrehan if (xpt_create_path(&sc->hs_path, /*periph*/NULL, 1097250199Sgrehan cam_sim_path(sc->hs_sim), 1098250199Sgrehan CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 1099250199Sgrehan xpt_bus_deregister(cam_sim_path(sc->hs_sim)); 1100250199Sgrehan cam_sim_free(sc->hs_sim, /*free_devq*/TRUE); 1101250199Sgrehan mtx_unlock(&sc->hs_lock); 1102250199Sgrehan device_printf(dev, "Unable to create path\n"); 1103250199Sgrehan ret = ENXIO; 1104250199Sgrehan goto cleanup; 1105250199Sgrehan } 1106250199Sgrehan 1107250199Sgrehan mtx_unlock(&sc->hs_lock); 1108250199Sgrehan 1109250199Sgrehan root_mount_rel(root_mount_token); 1110250199Sgrehan return (0); 1111250199Sgrehan 1112250199Sgrehan 1113250199Sgrehancleanup: 1114250199Sgrehan root_mount_rel(root_mount_token); 1115250199Sgrehan while (!LIST_EMPTY(&sc->hs_free_list)) { 1116250199Sgrehan reqp = LIST_FIRST(&sc->hs_free_list); 1117250199Sgrehan LIST_REMOVE(reqp, link); 1118250199Sgrehan free(reqp, M_DEVBUF); 1119250199Sgrehan } 1120283280Swhu 1121283280Swhu while (!LIST_EMPTY(&g_hv_sgl_page_pool.free_sgl_list)) { 1122283280Swhu sgl_node = LIST_FIRST(&g_hv_sgl_page_pool.free_sgl_list); 1123283280Swhu LIST_REMOVE(sgl_node, link); 1124283280Swhu for (j = 0; j < HV_MAX_MULTIPAGE_BUFFER_COUNT; j++) { 1125283280Swhu if (NULL != 1126283280Swhu (void*)sgl_node->sgl_data->sg_segs[j].ss_paddr) { 1127283280Swhu free((void*)sgl_node->sgl_data->sg_segs[j].ss_paddr, M_DEVBUF); 1128283280Swhu } 1129283280Swhu } 1130283280Swhu sglist_free(sgl_node->sgl_data); 1131283280Swhu free(sgl_node, M_DEVBUF); 1132283280Swhu } 1133283280Swhu 1134250199Sgrehan return (ret); 1135250199Sgrehan} 1136250199Sgrehan 1137250199Sgrehan/** 1138250199Sgrehan * @brief StorVSC device detach function 1139250199Sgrehan * 1140250199Sgrehan * This function is responsible for safely detaching a 1141250199Sgrehan * StorVSC device. This includes waiting for inbound responses 1142250199Sgrehan * to complete and freeing associated per-device structures. 1143250199Sgrehan * 1144250199Sgrehan * @param dev a device 1145250199Sgrehan * returns 0 on success 1146250199Sgrehan */ 1147250199Sgrehanstatic int 1148250199Sgrehanstorvsc_detach(device_t dev) 1149250199Sgrehan{ 1150250199Sgrehan struct storvsc_softc *sc = device_get_softc(dev); 1151250199Sgrehan struct hv_storvsc_request *reqp = NULL; 1152250199Sgrehan struct hv_device *hv_device = vmbus_get_devctx(dev); 1153283280Swhu struct hv_sgl_node *sgl_node = NULL; 1154283280Swhu int j = 0; 1155250199Sgrehan 1156250199Sgrehan mtx_lock(&hv_device->channel->inbound_lock); 1157250199Sgrehan sc->hs_destroy = TRUE; 1158250199Sgrehan mtx_unlock(&hv_device->channel->inbound_lock); 1159250199Sgrehan 1160250199Sgrehan /* 1161250199Sgrehan * At this point, all outbound traffic should be disabled. We 1162250199Sgrehan * only allow inbound traffic (responses) to proceed so that 1163250199Sgrehan * outstanding requests can be completed. 1164250199Sgrehan */ 1165250199Sgrehan 1166250199Sgrehan sc->hs_drain_notify = TRUE; 1167250199Sgrehan sema_wait(&sc->hs_drain_sema); 1168250199Sgrehan sc->hs_drain_notify = FALSE; 1169250199Sgrehan 1170250199Sgrehan /* 1171250199Sgrehan * Since we have already drained, we don't need to busy wait. 1172250199Sgrehan * The call to close the channel will reset the callback 1173250199Sgrehan * under the protection of the incoming channel lock. 1174250199Sgrehan */ 1175250199Sgrehan 1176250199Sgrehan hv_vmbus_channel_close(hv_device->channel); 1177250199Sgrehan 1178250199Sgrehan mtx_lock(&sc->hs_lock); 1179250199Sgrehan while (!LIST_EMPTY(&sc->hs_free_list)) { 1180250199Sgrehan reqp = LIST_FIRST(&sc->hs_free_list); 1181250199Sgrehan LIST_REMOVE(reqp, link); 1182250199Sgrehan 1183250199Sgrehan free(reqp, M_DEVBUF); 1184250199Sgrehan } 1185250199Sgrehan mtx_unlock(&sc->hs_lock); 1186283280Swhu 1187283280Swhu while (!LIST_EMPTY(&g_hv_sgl_page_pool.free_sgl_list)) { 1188283280Swhu sgl_node = LIST_FIRST(&g_hv_sgl_page_pool.free_sgl_list); 1189283280Swhu LIST_REMOVE(sgl_node, link); 1190283280Swhu for (j = 0; j < HV_MAX_MULTIPAGE_BUFFER_COUNT; j++){ 1191283280Swhu if (NULL != 1192283280Swhu (void*)sgl_node->sgl_data->sg_segs[j].ss_paddr) { 1193283280Swhu free((void*)sgl_node->sgl_data->sg_segs[j].ss_paddr, M_DEVBUF); 1194283280Swhu } 1195283280Swhu } 1196283280Swhu sglist_free(sgl_node->sgl_data); 1197283280Swhu free(sgl_node, M_DEVBUF); 1198283280Swhu } 1199283280Swhu 1200250199Sgrehan return (0); 1201250199Sgrehan} 1202250199Sgrehan 1203250199Sgrehan#if HVS_TIMEOUT_TEST 1204250199Sgrehan/** 1205250199Sgrehan * @brief unit test for timed out operations 1206250199Sgrehan * 1207250199Sgrehan * This function provides unit testing capability to simulate 1208250199Sgrehan * timed out operations. Recompilation with HV_TIMEOUT_TEST=1 1209250199Sgrehan * is required. 1210250199Sgrehan * 1211250199Sgrehan * @param reqp pointer to a request structure 1212250199Sgrehan * @param opcode SCSI operation being performed 1213250199Sgrehan * @param wait if 1, wait for I/O to complete 1214250199Sgrehan */ 1215250199Sgrehanstatic void 1216250199Sgrehanstorvsc_timeout_test(struct hv_storvsc_request *reqp, 1217250199Sgrehan uint8_t opcode, int wait) 1218250199Sgrehan{ 1219250199Sgrehan int ret; 1220250199Sgrehan union ccb *ccb = reqp->ccb; 1221250199Sgrehan struct storvsc_softc *sc = reqp->softc; 1222250199Sgrehan 1223250199Sgrehan if (reqp->vstor_packet.vm_srb.cdb[0] != opcode) { 1224250199Sgrehan return; 1225250199Sgrehan } 1226250199Sgrehan 1227250199Sgrehan if (wait) { 1228250199Sgrehan mtx_lock(&reqp->event.mtx); 1229250199Sgrehan } 1230250199Sgrehan ret = hv_storvsc_io_request(sc->hs_dev, reqp); 1231250199Sgrehan if (ret != 0) { 1232250199Sgrehan if (wait) { 1233250199Sgrehan mtx_unlock(&reqp->event.mtx); 1234250199Sgrehan } 1235250199Sgrehan printf("%s: io_request failed with %d.\n", 1236250199Sgrehan __func__, ret); 1237250199Sgrehan ccb->ccb_h.status = CAM_PROVIDE_FAIL; 1238250199Sgrehan mtx_lock(&sc->hs_lock); 1239250199Sgrehan storvsc_free_request(sc, reqp); 1240250199Sgrehan xpt_done(ccb); 1241250199Sgrehan mtx_unlock(&sc->hs_lock); 1242250199Sgrehan return; 1243250199Sgrehan } 1244250199Sgrehan 1245250199Sgrehan if (wait) { 1246250199Sgrehan xpt_print(ccb->ccb_h.path, 1247250199Sgrehan "%u: %s: waiting for IO return.\n", 1248250199Sgrehan ticks, __func__); 1249250199Sgrehan ret = cv_timedwait(&reqp->event.cv, &reqp->event.mtx, 60*hz); 1250250199Sgrehan mtx_unlock(&reqp->event.mtx); 1251250199Sgrehan xpt_print(ccb->ccb_h.path, "%u: %s: %s.\n", 1252250199Sgrehan ticks, __func__, (ret == 0)? 1253250199Sgrehan "IO return detected" : 1254250199Sgrehan "IO return not detected"); 1255283280Swhu /* 1256250199Sgrehan * Now both the timer handler and io done are running 1257250199Sgrehan * simultaneously. We want to confirm the io done always 1258250199Sgrehan * finishes after the timer handler exits. So reqp used by 1259250199Sgrehan * timer handler is not freed or stale. Do busy loop for 1260250199Sgrehan * another 1/10 second to make sure io done does 1261250199Sgrehan * wait for the timer handler to complete. 1262250199Sgrehan */ 1263250199Sgrehan DELAY(100*1000); 1264250199Sgrehan mtx_lock(&sc->hs_lock); 1265250199Sgrehan xpt_print(ccb->ccb_h.path, 1266250199Sgrehan "%u: %s: finishing, queue frozen %d, " 1267250199Sgrehan "ccb status 0x%x scsi_status 0x%x.\n", 1268250199Sgrehan ticks, __func__, sc->hs_frozen, 1269250199Sgrehan ccb->ccb_h.status, 1270250199Sgrehan ccb->csio.scsi_status); 1271250199Sgrehan mtx_unlock(&sc->hs_lock); 1272250199Sgrehan } 1273250199Sgrehan} 1274250199Sgrehan#endif /* HVS_TIMEOUT_TEST */ 1275250199Sgrehan 1276250199Sgrehan/** 1277250199Sgrehan * @brief timeout handler for requests 1278250199Sgrehan * 1279250199Sgrehan * This function is called as a result of a callout expiring. 1280250199Sgrehan * 1281250199Sgrehan * @param arg pointer to a request 1282250199Sgrehan */ 1283250199Sgrehanstatic void 1284250199Sgrehanstorvsc_timeout(void *arg) 1285250199Sgrehan{ 1286250199Sgrehan struct hv_storvsc_request *reqp = arg; 1287250199Sgrehan struct storvsc_softc *sc = reqp->softc; 1288250199Sgrehan union ccb *ccb = reqp->ccb; 1289250199Sgrehan 1290250199Sgrehan if (reqp->retries == 0) { 1291250199Sgrehan mtx_lock(&sc->hs_lock); 1292250199Sgrehan xpt_print(ccb->ccb_h.path, 1293250199Sgrehan "%u: IO timed out (req=0x%p), wait for another %u secs.\n", 1294250199Sgrehan ticks, reqp, ccb->ccb_h.timeout / 1000); 1295250199Sgrehan cam_error_print(ccb, CAM_ESF_ALL, CAM_EPF_ALL); 1296250199Sgrehan mtx_unlock(&sc->hs_lock); 1297250199Sgrehan 1298250199Sgrehan reqp->retries++; 1299275982Ssmh callout_reset_sbt(&reqp->callout, SBT_1MS * ccb->ccb_h.timeout, 1300275982Ssmh 0, storvsc_timeout, reqp, 0); 1301250199Sgrehan#if HVS_TIMEOUT_TEST 1302250199Sgrehan storvsc_timeout_test(reqp, SEND_DIAGNOSTIC, 0); 1303250199Sgrehan#endif 1304250199Sgrehan return; 1305250199Sgrehan } 1306250199Sgrehan 1307250199Sgrehan mtx_lock(&sc->hs_lock); 1308250199Sgrehan xpt_print(ccb->ccb_h.path, 1309250199Sgrehan "%u: IO (reqp = 0x%p) did not return for %u seconds, %s.\n", 1310250199Sgrehan ticks, reqp, ccb->ccb_h.timeout * (reqp->retries+1) / 1000, 1311250199Sgrehan (sc->hs_frozen == 0)? 1312250199Sgrehan "freezing the queue" : "the queue is already frozen"); 1313250199Sgrehan if (sc->hs_frozen == 0) { 1314250199Sgrehan sc->hs_frozen = 1; 1315250199Sgrehan xpt_freeze_simq(xpt_path_sim(ccb->ccb_h.path), 1); 1316250199Sgrehan } 1317250199Sgrehan mtx_unlock(&sc->hs_lock); 1318250199Sgrehan 1319250199Sgrehan#if HVS_TIMEOUT_TEST 1320250199Sgrehan storvsc_timeout_test(reqp, MODE_SELECT_10, 1); 1321250199Sgrehan#endif 1322250199Sgrehan} 1323250199Sgrehan 1324250199Sgrehan/** 1325250199Sgrehan * @brief StorVSC device poll function 1326250199Sgrehan * 1327250199Sgrehan * This function is responsible for servicing requests when 1328250199Sgrehan * interrupts are disabled (i.e when we are dumping core.) 1329250199Sgrehan * 1330250199Sgrehan * @param sim a pointer to a CAM SCSI interface module 1331250199Sgrehan */ 1332250199Sgrehanstatic void 1333250199Sgrehanstorvsc_poll(struct cam_sim *sim) 1334250199Sgrehan{ 1335250199Sgrehan struct storvsc_softc *sc = cam_sim_softc(sim); 1336250199Sgrehan 1337250199Sgrehan mtx_assert(&sc->hs_lock, MA_OWNED); 1338250199Sgrehan mtx_unlock(&sc->hs_lock); 1339283280Swhu hv_storvsc_on_channel_callback(sc->hs_dev->channel); 1340250199Sgrehan mtx_lock(&sc->hs_lock); 1341250199Sgrehan} 1342250199Sgrehan 1343250199Sgrehan/** 1344250199Sgrehan * @brief StorVSC device action function 1345250199Sgrehan * 1346250199Sgrehan * This function is responsible for handling SCSI operations which 1347250199Sgrehan * are passed from the CAM layer. The requests are in the form of 1348250199Sgrehan * CAM control blocks which indicate the action being performed. 1349250199Sgrehan * Not all actions require converting the request to a VSCSI protocol 1350250199Sgrehan * message - these actions can be responded to by this driver. 1351250199Sgrehan * Requests which are destined for a backend storage device are converted 1352250199Sgrehan * to a VSCSI protocol message and sent on the channel connection associated 1353250199Sgrehan * with this device. 1354250199Sgrehan * 1355250199Sgrehan * @param sim pointer to a CAM SCSI interface module 1356250199Sgrehan * @param ccb pointer to a CAM control block 1357250199Sgrehan */ 1358250199Sgrehanstatic void 1359250199Sgrehanstorvsc_action(struct cam_sim *sim, union ccb *ccb) 1360250199Sgrehan{ 1361250199Sgrehan struct storvsc_softc *sc = cam_sim_softc(sim); 1362250199Sgrehan int res; 1363250199Sgrehan 1364250199Sgrehan mtx_assert(&sc->hs_lock, MA_OWNED); 1365250199Sgrehan switch (ccb->ccb_h.func_code) { 1366250199Sgrehan case XPT_PATH_INQ: { 1367250199Sgrehan struct ccb_pathinq *cpi = &ccb->cpi; 1368250199Sgrehan 1369250199Sgrehan cpi->version_num = 1; 1370250199Sgrehan cpi->hba_inquiry = PI_TAG_ABLE|PI_SDTR_ABLE; 1371250199Sgrehan cpi->target_sprt = 0; 1372250199Sgrehan cpi->hba_misc = PIM_NOBUSRESET; 1373250199Sgrehan cpi->hba_eng_cnt = 0; 1374250199Sgrehan cpi->max_target = STORVSC_MAX_TARGETS; 1375250199Sgrehan cpi->max_lun = sc->hs_drv_props->drv_max_luns_per_target; 1376263065Smav cpi->initiator_id = cpi->max_target; 1377250199Sgrehan cpi->bus_id = cam_sim_bus(sim); 1378250199Sgrehan cpi->base_transfer_speed = 300000; 1379250199Sgrehan cpi->transport = XPORT_SAS; 1380250199Sgrehan cpi->transport_version = 0; 1381250199Sgrehan cpi->protocol = PROTO_SCSI; 1382250199Sgrehan cpi->protocol_version = SCSI_REV_SPC2; 1383250199Sgrehan strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 1384250199Sgrehan strncpy(cpi->hba_vid, sc->hs_drv_props->drv_name, HBA_IDLEN); 1385250199Sgrehan strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 1386250199Sgrehan cpi->unit_number = cam_sim_unit(sim); 1387250199Sgrehan 1388250199Sgrehan ccb->ccb_h.status = CAM_REQ_CMP; 1389250199Sgrehan xpt_done(ccb); 1390250199Sgrehan return; 1391250199Sgrehan } 1392250199Sgrehan case XPT_GET_TRAN_SETTINGS: { 1393250199Sgrehan struct ccb_trans_settings *cts = &ccb->cts; 1394250199Sgrehan 1395250199Sgrehan cts->transport = XPORT_SAS; 1396250199Sgrehan cts->transport_version = 0; 1397250199Sgrehan cts->protocol = PROTO_SCSI; 1398250199Sgrehan cts->protocol_version = SCSI_REV_SPC2; 1399250199Sgrehan 1400250199Sgrehan /* enable tag queuing and disconnected mode */ 1401250199Sgrehan cts->proto_specific.valid = CTS_SCSI_VALID_TQ; 1402250199Sgrehan cts->proto_specific.scsi.valid = CTS_SCSI_VALID_TQ; 1403250199Sgrehan cts->proto_specific.scsi.flags = CTS_SCSI_FLAGS_TAG_ENB; 1404250199Sgrehan cts->xport_specific.valid = CTS_SPI_VALID_DISC; 1405250199Sgrehan cts->xport_specific.spi.flags = CTS_SPI_FLAGS_DISC_ENB; 1406250199Sgrehan 1407250199Sgrehan ccb->ccb_h.status = CAM_REQ_CMP; 1408250199Sgrehan xpt_done(ccb); 1409250199Sgrehan return; 1410250199Sgrehan } 1411250199Sgrehan case XPT_SET_TRAN_SETTINGS: { 1412250199Sgrehan ccb->ccb_h.status = CAM_REQ_CMP; 1413250199Sgrehan xpt_done(ccb); 1414250199Sgrehan return; 1415250199Sgrehan } 1416250199Sgrehan case XPT_CALC_GEOMETRY:{ 1417250199Sgrehan cam_calc_geometry(&ccb->ccg, 1); 1418250199Sgrehan xpt_done(ccb); 1419250199Sgrehan return; 1420250199Sgrehan } 1421250199Sgrehan case XPT_RESET_BUS: 1422250199Sgrehan case XPT_RESET_DEV:{ 1423250199Sgrehan#if HVS_HOST_RESET 1424250199Sgrehan if ((res = hv_storvsc_host_reset(sc->hs_dev)) != 0) { 1425250199Sgrehan xpt_print(ccb->ccb_h.path, 1426250199Sgrehan "hv_storvsc_host_reset failed with %d\n", res); 1427250199Sgrehan ccb->ccb_h.status = CAM_PROVIDE_FAIL; 1428250199Sgrehan xpt_done(ccb); 1429250199Sgrehan return; 1430250199Sgrehan } 1431250199Sgrehan ccb->ccb_h.status = CAM_REQ_CMP; 1432250199Sgrehan xpt_done(ccb); 1433250199Sgrehan return; 1434250199Sgrehan#else 1435250199Sgrehan xpt_print(ccb->ccb_h.path, 1436250199Sgrehan "%s reset not supported.\n", 1437250199Sgrehan (ccb->ccb_h.func_code == XPT_RESET_BUS)? 1438250199Sgrehan "bus" : "dev"); 1439250199Sgrehan ccb->ccb_h.status = CAM_REQ_INVALID; 1440250199Sgrehan xpt_done(ccb); 1441250199Sgrehan return; 1442250199Sgrehan#endif /* HVS_HOST_RESET */ 1443250199Sgrehan } 1444250199Sgrehan case XPT_SCSI_IO: 1445250199Sgrehan case XPT_IMMED_NOTIFY: { 1446250199Sgrehan struct hv_storvsc_request *reqp = NULL; 1447250199Sgrehan 1448250199Sgrehan if (ccb->csio.cdb_len == 0) { 1449250199Sgrehan panic("cdl_len is 0\n"); 1450250199Sgrehan } 1451250199Sgrehan 1452250199Sgrehan if (LIST_EMPTY(&sc->hs_free_list)) { 1453250199Sgrehan ccb->ccb_h.status = CAM_REQUEUE_REQ; 1454250199Sgrehan if (sc->hs_frozen == 0) { 1455250199Sgrehan sc->hs_frozen = 1; 1456250199Sgrehan xpt_freeze_simq(sim, /* count*/1); 1457250199Sgrehan } 1458250199Sgrehan xpt_done(ccb); 1459250199Sgrehan return; 1460250199Sgrehan } 1461250199Sgrehan 1462250199Sgrehan reqp = LIST_FIRST(&sc->hs_free_list); 1463250199Sgrehan LIST_REMOVE(reqp, link); 1464250199Sgrehan 1465250199Sgrehan bzero(reqp, sizeof(struct hv_storvsc_request)); 1466250199Sgrehan reqp->softc = sc; 1467283280Swhu 1468283280Swhu ccb->ccb_h.status |= CAM_SIM_QUEUED; 1469283280Swhu if ((res = create_storvsc_request(ccb, reqp)) != 0) { 1470283280Swhu ccb->ccb_h.status = CAM_REQ_INVALID; 1471283280Swhu xpt_done(ccb); 1472283280Swhu return; 1473283280Swhu } 1474250199Sgrehan 1475250199Sgrehan if (ccb->ccb_h.timeout != CAM_TIME_INFINITY) { 1476250199Sgrehan callout_init(&reqp->callout, CALLOUT_MPSAFE); 1477275982Ssmh callout_reset_sbt(&reqp->callout, 1478275982Ssmh SBT_1MS * ccb->ccb_h.timeout, 0, 1479275982Ssmh storvsc_timeout, reqp, 0); 1480250199Sgrehan#if HVS_TIMEOUT_TEST 1481250199Sgrehan cv_init(&reqp->event.cv, "storvsc timeout cv"); 1482250199Sgrehan mtx_init(&reqp->event.mtx, "storvsc timeout mutex", 1483250199Sgrehan NULL, MTX_DEF); 1484250199Sgrehan switch (reqp->vstor_packet.vm_srb.cdb[0]) { 1485250199Sgrehan case MODE_SELECT_10: 1486250199Sgrehan case SEND_DIAGNOSTIC: 1487250199Sgrehan /* To have timer send the request. */ 1488250199Sgrehan return; 1489250199Sgrehan default: 1490250199Sgrehan break; 1491250199Sgrehan } 1492250199Sgrehan#endif /* HVS_TIMEOUT_TEST */ 1493250199Sgrehan } 1494250199Sgrehan 1495250199Sgrehan if ((res = hv_storvsc_io_request(sc->hs_dev, reqp)) != 0) { 1496250199Sgrehan xpt_print(ccb->ccb_h.path, 1497250199Sgrehan "hv_storvsc_io_request failed with %d\n", res); 1498250199Sgrehan ccb->ccb_h.status = CAM_PROVIDE_FAIL; 1499250199Sgrehan storvsc_free_request(sc, reqp); 1500250199Sgrehan xpt_done(ccb); 1501250199Sgrehan return; 1502250199Sgrehan } 1503250199Sgrehan return; 1504250199Sgrehan } 1505250199Sgrehan 1506250199Sgrehan default: 1507250199Sgrehan ccb->ccb_h.status = CAM_REQ_INVALID; 1508250199Sgrehan xpt_done(ccb); 1509250199Sgrehan return; 1510250199Sgrehan } 1511250199Sgrehan} 1512250199Sgrehan 1513250199Sgrehan/** 1514283280Swhu * @brief destroy bounce buffer 1515283280Swhu * 1516283280Swhu * This function is responsible for destroy a Scatter/Gather list 1517283280Swhu * that create by storvsc_create_bounce_buffer() 1518283280Swhu * 1519283280Swhu * @param sgl- the Scatter/Gather need be destroy 1520283280Swhu * @param sg_count- page count of the SG list. 1521283280Swhu * 1522283280Swhu */ 1523283280Swhustatic void 1524283280Swhustorvsc_destroy_bounce_buffer(struct sglist *sgl) 1525283280Swhu{ 1526283280Swhu struct hv_sgl_node *sgl_node = NULL; 1527283280Swhu 1528283280Swhu sgl_node = LIST_FIRST(&g_hv_sgl_page_pool.in_use_sgl_list); 1529283280Swhu LIST_REMOVE(sgl_node, link); 1530283280Swhu if (NULL == sgl_node) { 1531283280Swhu printf("storvsc error: not enough in use sgl\n"); 1532283280Swhu return; 1533283280Swhu } 1534283280Swhu sgl_node->sgl_data = sgl; 1535283280Swhu LIST_INSERT_HEAD(&g_hv_sgl_page_pool.free_sgl_list, sgl_node, link); 1536283280Swhu} 1537283280Swhu 1538283280Swhu/** 1539283280Swhu * @brief create bounce buffer 1540283280Swhu * 1541283280Swhu * This function is responsible for create a Scatter/Gather list, 1542283280Swhu * which hold several pages that can be aligned with page size. 1543283280Swhu * 1544283280Swhu * @param seg_count- SG-list segments count 1545283280Swhu * @param write - if WRITE_TYPE, set SG list page used size to 0, 1546283280Swhu * otherwise set used size to page size. 1547283280Swhu * 1548283280Swhu * return NULL if create failed 1549283280Swhu */ 1550283280Swhustatic struct sglist * 1551283280Swhustorvsc_create_bounce_buffer(uint16_t seg_count, int write) 1552283280Swhu{ 1553283280Swhu int i = 0; 1554283280Swhu struct sglist *bounce_sgl = NULL; 1555283280Swhu unsigned int buf_len = ((write == WRITE_TYPE) ? 0 : PAGE_SIZE); 1556283280Swhu struct hv_sgl_node *sgl_node = NULL; 1557283280Swhu 1558283280Swhu /* get struct sglist from free_sgl_list */ 1559283280Swhu sgl_node = LIST_FIRST(&g_hv_sgl_page_pool.free_sgl_list); 1560283280Swhu LIST_REMOVE(sgl_node, link); 1561283280Swhu if (NULL == sgl_node) { 1562283280Swhu printf("storvsc error: not enough free sgl\n"); 1563283280Swhu return NULL; 1564283280Swhu } 1565283280Swhu bounce_sgl = sgl_node->sgl_data; 1566283280Swhu LIST_INSERT_HEAD(&g_hv_sgl_page_pool.in_use_sgl_list, sgl_node, link); 1567283280Swhu 1568283280Swhu bounce_sgl->sg_maxseg = seg_count; 1569283280Swhu 1570283280Swhu if (write == WRITE_TYPE) 1571283280Swhu bounce_sgl->sg_nseg = 0; 1572283280Swhu else 1573283280Swhu bounce_sgl->sg_nseg = seg_count; 1574283280Swhu 1575283280Swhu for (i = 0; i < seg_count; i++) 1576283280Swhu bounce_sgl->sg_segs[i].ss_len = buf_len; 1577283280Swhu 1578283280Swhu return bounce_sgl; 1579283280Swhu} 1580283280Swhu 1581283280Swhu/** 1582283280Swhu * @brief copy data from SG list to bounce buffer 1583283280Swhu * 1584283280Swhu * This function is responsible for copy data from one SG list's segments 1585283280Swhu * to another SG list which used as bounce buffer. 1586283280Swhu * 1587283280Swhu * @param bounce_sgl - the destination SG list 1588283280Swhu * @param orig_sgl - the segment of the source SG list. 1589283280Swhu * @param orig_sgl_count - the count of segments. 1590283280Swhu * @param orig_sgl_count - indicate which segment need bounce buffer, 1591283280Swhu * set 1 means need. 1592283280Swhu * 1593283280Swhu */ 1594283280Swhustatic void 1595283280Swhustorvsc_copy_sgl_to_bounce_buf(struct sglist *bounce_sgl, 1596283280Swhu bus_dma_segment_t *orig_sgl, 1597283280Swhu unsigned int orig_sgl_count, 1598283280Swhu uint64_t seg_bits) 1599283280Swhu{ 1600283280Swhu int src_sgl_idx = 0; 1601283280Swhu 1602283280Swhu for (src_sgl_idx = 0; src_sgl_idx < orig_sgl_count; src_sgl_idx++) { 1603283280Swhu if (seg_bits & (1 << src_sgl_idx)) { 1604283280Swhu memcpy((void*)bounce_sgl->sg_segs[src_sgl_idx].ss_paddr, 1605283280Swhu (void*)orig_sgl[src_sgl_idx].ds_addr, 1606283280Swhu orig_sgl[src_sgl_idx].ds_len); 1607283280Swhu 1608283280Swhu bounce_sgl->sg_segs[src_sgl_idx].ss_len = 1609283280Swhu orig_sgl[src_sgl_idx].ds_len; 1610283280Swhu } 1611283280Swhu } 1612283280Swhu} 1613283280Swhu 1614283280Swhu/** 1615283280Swhu * @brief copy data from SG list which used as bounce to another SG list 1616283280Swhu * 1617283280Swhu * This function is responsible for copy data from one SG list with bounce 1618283280Swhu * buffer to another SG list's segments. 1619283280Swhu * 1620283280Swhu * @param dest_sgl - the destination SG list's segments 1621283280Swhu * @param dest_sgl_count - the count of destination SG list's segment. 1622283280Swhu * @param src_sgl - the source SG list. 1623283280Swhu * @param seg_bits - indicate which segment used bounce buffer of src SG-list. 1624283280Swhu * 1625283280Swhu */ 1626283280Swhuvoid 1627283280Swhustorvsc_copy_from_bounce_buf_to_sgl(bus_dma_segment_t *dest_sgl, 1628283280Swhu unsigned int dest_sgl_count, 1629283280Swhu struct sglist* src_sgl, 1630283280Swhu uint64_t seg_bits) 1631283280Swhu{ 1632283280Swhu int sgl_idx = 0; 1633283280Swhu 1634283280Swhu for (sgl_idx = 0; sgl_idx < dest_sgl_count; sgl_idx++) { 1635283280Swhu if (seg_bits & (1 << sgl_idx)) { 1636283280Swhu memcpy((void*)(dest_sgl[sgl_idx].ds_addr), 1637283280Swhu (void*)(src_sgl->sg_segs[sgl_idx].ss_paddr), 1638283280Swhu src_sgl->sg_segs[sgl_idx].ss_len); 1639283280Swhu } 1640283280Swhu } 1641283280Swhu} 1642283280Swhu 1643283280Swhu/** 1644283280Swhu * @brief check SG list with bounce buffer or not 1645283280Swhu * 1646283280Swhu * This function is responsible for check if need bounce buffer for SG list. 1647283280Swhu * 1648283280Swhu * @param sgl - the SG list's segments 1649283280Swhu * @param sg_count - the count of SG list's segment. 1650283280Swhu * @param bits - segmengs number that need bounce buffer 1651283280Swhu * 1652283280Swhu * return -1 if SG list needless bounce buffer 1653283280Swhu */ 1654283280Swhustatic int 1655283280Swhustorvsc_check_bounce_buffer_sgl(bus_dma_segment_t *sgl, 1656283280Swhu unsigned int sg_count, 1657283280Swhu uint64_t *bits) 1658283280Swhu{ 1659283280Swhu int i = 0; 1660283280Swhu int offset = 0; 1661283280Swhu uint64_t phys_addr = 0; 1662283280Swhu uint64_t tmp_bits = 0; 1663283280Swhu boolean_t found_hole = FALSE; 1664283280Swhu boolean_t pre_aligned = TRUE; 1665283280Swhu 1666283280Swhu if (sg_count < 2){ 1667283280Swhu return -1; 1668283280Swhu } 1669283280Swhu 1670283280Swhu *bits = 0; 1671283280Swhu 1672283280Swhu phys_addr = vtophys(sgl[0].ds_addr); 1673283280Swhu offset = phys_addr - trunc_page(phys_addr); 1674283280Swhu 1675283280Swhu if (offset != 0) { 1676283280Swhu pre_aligned = FALSE; 1677283280Swhu tmp_bits |= 1; 1678283280Swhu } 1679283280Swhu 1680283280Swhu for (i = 1; i < sg_count; i++) { 1681283280Swhu phys_addr = vtophys(sgl[i].ds_addr); 1682283280Swhu offset = phys_addr - trunc_page(phys_addr); 1683283280Swhu 1684283280Swhu if (offset == 0) { 1685283280Swhu if (FALSE == pre_aligned){ 1686283280Swhu /* 1687283280Swhu * This segment is aligned, if the previous 1688283280Swhu * one is not aligned, find a hole 1689283280Swhu */ 1690283280Swhu found_hole = TRUE; 1691283280Swhu } 1692283280Swhu pre_aligned = TRUE; 1693283280Swhu } else { 1694283280Swhu tmp_bits |= 1 << i; 1695283280Swhu if (!pre_aligned) { 1696283280Swhu if (phys_addr != vtophys(sgl[i-1].ds_addr + 1697283280Swhu sgl[i-1].ds_len)) { 1698283280Swhu /* 1699283280Swhu * Check whether connect to previous 1700283280Swhu * segment,if not, find the hole 1701283280Swhu */ 1702283280Swhu found_hole = TRUE; 1703283280Swhu } 1704283280Swhu } else { 1705283280Swhu found_hole = TRUE; 1706283280Swhu } 1707283280Swhu pre_aligned = FALSE; 1708283280Swhu } 1709283280Swhu } 1710283280Swhu 1711283280Swhu if (!found_hole) { 1712283280Swhu return (-1); 1713283280Swhu } else { 1714283280Swhu *bits = tmp_bits; 1715283280Swhu return 0; 1716283280Swhu } 1717283280Swhu} 1718283280Swhu 1719283280Swhu/** 1720250199Sgrehan * @brief Fill in a request structure based on a CAM control block 1721250199Sgrehan * 1722250199Sgrehan * Fills in a request structure based on the contents of a CAM control 1723250199Sgrehan * block. The request structure holds the payload information for 1724250199Sgrehan * VSCSI protocol request. 1725250199Sgrehan * 1726250199Sgrehan * @param ccb pointer to a CAM contorl block 1727250199Sgrehan * @param reqp pointer to a request structure 1728250199Sgrehan */ 1729283280Swhustatic int 1730250199Sgrehancreate_storvsc_request(union ccb *ccb, struct hv_storvsc_request *reqp) 1731250199Sgrehan{ 1732250199Sgrehan struct ccb_scsiio *csio = &ccb->csio; 1733250199Sgrehan uint64_t phys_addr; 1734250199Sgrehan uint32_t bytes_to_copy = 0; 1735250199Sgrehan uint32_t pfn_num = 0; 1736250199Sgrehan uint32_t pfn; 1737283280Swhu uint64_t not_aligned_seg_bits = 0; 1738250199Sgrehan 1739250199Sgrehan /* refer to struct vmscsi_req for meanings of these two fields */ 1740256276Sdim reqp->vstor_packet.u.vm_srb.port = 1741250199Sgrehan cam_sim_unit(xpt_path_sim(ccb->ccb_h.path)); 1742256276Sdim reqp->vstor_packet.u.vm_srb.path_id = 1743250199Sgrehan cam_sim_bus(xpt_path_sim(ccb->ccb_h.path)); 1744250199Sgrehan 1745256276Sdim reqp->vstor_packet.u.vm_srb.target_id = ccb->ccb_h.target_id; 1746256276Sdim reqp->vstor_packet.u.vm_srb.lun = ccb->ccb_h.target_lun; 1747250199Sgrehan 1748256276Sdim reqp->vstor_packet.u.vm_srb.cdb_len = csio->cdb_len; 1749250199Sgrehan if(ccb->ccb_h.flags & CAM_CDB_POINTER) { 1750256276Sdim memcpy(&reqp->vstor_packet.u.vm_srb.u.cdb, csio->cdb_io.cdb_ptr, 1751250199Sgrehan csio->cdb_len); 1752250199Sgrehan } else { 1753256276Sdim memcpy(&reqp->vstor_packet.u.vm_srb.u.cdb, csio->cdb_io.cdb_bytes, 1754250199Sgrehan csio->cdb_len); 1755250199Sgrehan } 1756250199Sgrehan 1757250199Sgrehan switch (ccb->ccb_h.flags & CAM_DIR_MASK) { 1758283280Swhu case CAM_DIR_OUT: 1759283280Swhu reqp->vstor_packet.u.vm_srb.data_in = WRITE_TYPE; 1760283280Swhu break; 1761283280Swhu case CAM_DIR_IN: 1762283280Swhu reqp->vstor_packet.u.vm_srb.data_in = READ_TYPE; 1763283280Swhu break; 1764283280Swhu case CAM_DIR_NONE: 1765283280Swhu reqp->vstor_packet.u.vm_srb.data_in = UNKNOWN_TYPE; 1766283280Swhu break; 1767283280Swhu default: 1768283280Swhu reqp->vstor_packet.u.vm_srb.data_in = UNKNOWN_TYPE; 1769283280Swhu break; 1770250199Sgrehan } 1771250199Sgrehan 1772250199Sgrehan reqp->sense_data = &csio->sense_data; 1773250199Sgrehan reqp->sense_info_len = csio->sense_len; 1774250199Sgrehan 1775250199Sgrehan reqp->ccb = ccb; 1776283280Swhu 1777283280Swhu if (0 == csio->dxfer_len) { 1778283280Swhu return (0); 1779283280Swhu } 1780283280Swhu 1781283280Swhu reqp->data_buf.length = csio->dxfer_len; 1782283280Swhu 1783283280Swhu switch (ccb->ccb_h.flags & CAM_DATA_MASK) { 1784283280Swhu case CAM_DATA_VADDR: 1785283280Swhu { 1786250199Sgrehan bytes_to_copy = csio->dxfer_len; 1787250199Sgrehan phys_addr = vtophys(csio->data_ptr); 1788283280Swhu reqp->data_buf.offset = phys_addr & PAGE_MASK; 1789283280Swhu 1790283280Swhu while (bytes_to_copy != 0) { 1791283280Swhu int bytes, page_offset; 1792283280Swhu phys_addr = 1793283280Swhu vtophys(&csio->data_ptr[reqp->data_buf.length - 1794283280Swhu bytes_to_copy]); 1795283280Swhu pfn = phys_addr >> PAGE_SHIFT; 1796283280Swhu reqp->data_buf.pfn_array[pfn_num] = pfn; 1797283280Swhu page_offset = phys_addr & PAGE_MASK; 1798283280Swhu 1799283280Swhu bytes = min(PAGE_SIZE - page_offset, bytes_to_copy); 1800283280Swhu 1801283280Swhu bytes_to_copy -= bytes; 1802283280Swhu pfn_num++; 1803283280Swhu } 1804283280Swhu break; 1805250199Sgrehan } 1806250199Sgrehan 1807283280Swhu case CAM_DATA_SG: 1808283280Swhu { 1809283280Swhu int i = 0; 1810283280Swhu int offset = 0; 1811283280Swhu int ret; 1812250199Sgrehan 1813283280Swhu bus_dma_segment_t *storvsc_sglist = 1814283280Swhu (bus_dma_segment_t *)ccb->csio.data_ptr; 1815283280Swhu u_int16_t storvsc_sg_count = ccb->csio.sglist_cnt; 1816250199Sgrehan 1817283280Swhu printf("Storvsc: get SG I/O operation, %d\n", 1818283280Swhu reqp->vstor_packet.u.vm_srb.data_in); 1819283280Swhu 1820283280Swhu if (storvsc_sg_count > HV_MAX_MULTIPAGE_BUFFER_COUNT){ 1821283280Swhu printf("Storvsc: %d segments is too much, " 1822283280Swhu "only support %d segments\n", 1823283280Swhu storvsc_sg_count, HV_MAX_MULTIPAGE_BUFFER_COUNT); 1824283280Swhu return (EINVAL); 1825283280Swhu } 1826283280Swhu 1827283280Swhu /* 1828283280Swhu * We create our own bounce buffer function currently. Idealy 1829283280Swhu * we should use BUS_DMA(9) framework. But with current BUS_DMA 1830283280Swhu * code there is no callback API to check the page alignment of 1831283280Swhu * middle segments before busdma can decide if a bounce buffer 1832283280Swhu * is needed for particular segment. There is callback, 1833283280Swhu * "bus_dma_filter_t *filter", but the parrameters are not 1834283280Swhu * sufficient for storvsc driver. 1835283280Swhu * TODO: 1836283280Swhu * Add page alignment check in BUS_DMA(9) callback. Once 1837283280Swhu * this is complete, switch the following code to use 1838283280Swhu * BUS_DMA(9) for storvsc bounce buffer support. 1839283280Swhu */ 1840283280Swhu /* check if we need to create bounce buffer */ 1841283280Swhu ret = storvsc_check_bounce_buffer_sgl(storvsc_sglist, 1842283280Swhu storvsc_sg_count, ¬_aligned_seg_bits); 1843283280Swhu if (ret != -1) { 1844283280Swhu reqp->bounce_sgl = 1845283280Swhu storvsc_create_bounce_buffer(storvsc_sg_count, 1846283280Swhu reqp->vstor_packet.u.vm_srb.data_in); 1847283280Swhu if (NULL == reqp->bounce_sgl) { 1848283280Swhu printf("Storvsc_error: " 1849283280Swhu "create bounce buffer failed.\n"); 1850283280Swhu return (ENOMEM); 1851283280Swhu } 1852283280Swhu 1853283280Swhu reqp->bounce_sgl_count = storvsc_sg_count; 1854283280Swhu reqp->not_aligned_seg_bits = not_aligned_seg_bits; 1855283280Swhu 1856283280Swhu /* 1857283280Swhu * if it is write, we need copy the original data 1858283280Swhu *to bounce buffer 1859283280Swhu */ 1860283280Swhu if (WRITE_TYPE == reqp->vstor_packet.u.vm_srb.data_in) { 1861283280Swhu storvsc_copy_sgl_to_bounce_buf( 1862283280Swhu reqp->bounce_sgl, 1863283280Swhu storvsc_sglist, 1864283280Swhu storvsc_sg_count, 1865283280Swhu reqp->not_aligned_seg_bits); 1866283280Swhu } 1867283280Swhu 1868283280Swhu /* transfer virtual address to physical frame number */ 1869283280Swhu if (reqp->not_aligned_seg_bits & 0x1){ 1870283280Swhu phys_addr = 1871283280Swhu vtophys(reqp->bounce_sgl->sg_segs[0].ss_paddr); 1872283280Swhu }else{ 1873283280Swhu phys_addr = 1874283280Swhu vtophys(storvsc_sglist[0].ds_addr); 1875283280Swhu } 1876283280Swhu reqp->data_buf.offset = phys_addr & PAGE_MASK; 1877283280Swhu 1878283280Swhu pfn = phys_addr >> PAGE_SHIFT; 1879283280Swhu reqp->data_buf.pfn_array[0] = pfn; 1880283280Swhu 1881283280Swhu for (i = 1; i < storvsc_sg_count; i++) { 1882283280Swhu if (reqp->not_aligned_seg_bits & (1 << i)) { 1883283280Swhu phys_addr = 1884283280Swhu vtophys(reqp->bounce_sgl->sg_segs[i].ss_paddr); 1885283280Swhu } else { 1886283280Swhu phys_addr = 1887283280Swhu vtophys(storvsc_sglist[i].ds_addr); 1888283280Swhu } 1889283280Swhu 1890283280Swhu pfn = phys_addr >> PAGE_SHIFT; 1891283280Swhu reqp->data_buf.pfn_array[i] = pfn; 1892283280Swhu } 1893283280Swhu } else { 1894283280Swhu phys_addr = vtophys(storvsc_sglist[0].ds_addr); 1895283280Swhu 1896283280Swhu reqp->data_buf.offset = phys_addr & PAGE_MASK; 1897283280Swhu 1898283280Swhu for (i = 0; i < storvsc_sg_count; i++) { 1899283280Swhu phys_addr = vtophys(storvsc_sglist[i].ds_addr); 1900283280Swhu pfn = phys_addr >> PAGE_SHIFT; 1901283280Swhu reqp->data_buf.pfn_array[i] = pfn; 1902283280Swhu } 1903283280Swhu 1904283280Swhu /* check the last segment cross boundary or not */ 1905283280Swhu offset = phys_addr & PAGE_MASK; 1906283280Swhu if (offset) { 1907283280Swhu phys_addr = 1908283280Swhu vtophys(storvsc_sglist[i-1].ds_addr + 1909283280Swhu PAGE_SIZE - offset); 1910283280Swhu pfn = phys_addr >> PAGE_SHIFT; 1911283280Swhu reqp->data_buf.pfn_array[i] = pfn; 1912283280Swhu } 1913283280Swhu 1914283280Swhu reqp->bounce_sgl_count = 0; 1915283280Swhu } 1916283280Swhu break; 1917250199Sgrehan } 1918283280Swhu default: 1919283280Swhu printf("Unknow flags: %d\n", ccb->ccb_h.flags); 1920283280Swhu return(EINVAL); 1921283280Swhu } 1922283280Swhu 1923283280Swhu return(0); 1924250199Sgrehan} 1925250199Sgrehan 1926250199Sgrehan/** 1927250199Sgrehan * @brief completion function before returning to CAM 1928250199Sgrehan * 1929250199Sgrehan * I/O process has been completed and the result needs 1930250199Sgrehan * to be passed to the CAM layer. 1931250199Sgrehan * Free resources related to this request. 1932250199Sgrehan * 1933250199Sgrehan * @param reqp pointer to a request structure 1934250199Sgrehan */ 1935250199Sgrehanstatic void 1936250199Sgrehanstorvsc_io_done(struct hv_storvsc_request *reqp) 1937250199Sgrehan{ 1938250199Sgrehan union ccb *ccb = reqp->ccb; 1939250199Sgrehan struct ccb_scsiio *csio = &ccb->csio; 1940250199Sgrehan struct storvsc_softc *sc = reqp->softc; 1941256276Sdim struct vmscsi_req *vm_srb = &reqp->vstor_packet.u.vm_srb; 1942283280Swhu bus_dma_segment_t *ori_sglist = NULL; 1943283280Swhu int ori_sg_count = 0; 1944283280Swhu 1945283280Swhu /* destroy bounce buffer if it is used */ 1946283280Swhu if (reqp->bounce_sgl_count) { 1947283280Swhu ori_sglist = (bus_dma_segment_t *)ccb->csio.data_ptr; 1948283280Swhu ori_sg_count = ccb->csio.sglist_cnt; 1949283280Swhu 1950283280Swhu /* 1951283280Swhu * If it is READ operation, we should copy back the data 1952283280Swhu * to original SG list. 1953283280Swhu */ 1954283280Swhu if (READ_TYPE == reqp->vstor_packet.u.vm_srb.data_in) { 1955283280Swhu storvsc_copy_from_bounce_buf_to_sgl(ori_sglist, 1956283280Swhu ori_sg_count, 1957283280Swhu reqp->bounce_sgl, 1958283280Swhu reqp->not_aligned_seg_bits); 1959283280Swhu } 1960283280Swhu 1961283280Swhu storvsc_destroy_bounce_buffer(reqp->bounce_sgl); 1962283280Swhu reqp->bounce_sgl_count = 0; 1963283280Swhu } 1964283280Swhu 1965250199Sgrehan if (reqp->retries > 0) { 1966250199Sgrehan mtx_lock(&sc->hs_lock); 1967250199Sgrehan#if HVS_TIMEOUT_TEST 1968250199Sgrehan xpt_print(ccb->ccb_h.path, 1969250199Sgrehan "%u: IO returned after timeout, " 1970250199Sgrehan "waking up timer handler if any.\n", ticks); 1971250199Sgrehan mtx_lock(&reqp->event.mtx); 1972250199Sgrehan cv_signal(&reqp->event.cv); 1973250199Sgrehan mtx_unlock(&reqp->event.mtx); 1974250199Sgrehan#endif 1975250199Sgrehan reqp->retries = 0; 1976250199Sgrehan xpt_print(ccb->ccb_h.path, 1977250199Sgrehan "%u: IO returned after timeout, " 1978250199Sgrehan "stopping timer if any.\n", ticks); 1979250199Sgrehan mtx_unlock(&sc->hs_lock); 1980250199Sgrehan } 1981250199Sgrehan 1982283280Swhu /* 1983250199Sgrehan * callout_drain() will wait for the timer handler to finish 1984250199Sgrehan * if it is running. So we don't need any lock to synchronize 1985250199Sgrehan * between this routine and the timer handler. 1986250199Sgrehan * Note that we need to make sure reqp is not freed when timer 1987250199Sgrehan * handler is using or will use it. 1988250199Sgrehan */ 1989250199Sgrehan if (ccb->ccb_h.timeout != CAM_TIME_INFINITY) { 1990250199Sgrehan callout_drain(&reqp->callout); 1991250199Sgrehan } 1992250199Sgrehan 1993250199Sgrehan ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 1994250199Sgrehan ccb->ccb_h.status &= ~CAM_STATUS_MASK; 1995250199Sgrehan if (vm_srb->scsi_status == SCSI_STATUS_OK) { 1996250199Sgrehan ccb->ccb_h.status |= CAM_REQ_CMP; 1997250199Sgrehan } else { 1998250199Sgrehan mtx_lock(&sc->hs_lock); 1999250199Sgrehan xpt_print(ccb->ccb_h.path, 2000250199Sgrehan "srovsc scsi_status = %d\n", 2001250199Sgrehan vm_srb->scsi_status); 2002250199Sgrehan mtx_unlock(&sc->hs_lock); 2003250199Sgrehan ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR; 2004250199Sgrehan } 2005250199Sgrehan 2006250199Sgrehan ccb->csio.scsi_status = (vm_srb->scsi_status & 0xFF); 2007250199Sgrehan ccb->csio.resid = ccb->csio.dxfer_len - vm_srb->transfer_len; 2008250199Sgrehan 2009250199Sgrehan if (reqp->sense_info_len != 0) { 2010250199Sgrehan csio->sense_resid = csio->sense_len - reqp->sense_info_len; 2011250199Sgrehan ccb->ccb_h.status |= CAM_AUTOSNS_VALID; 2012250199Sgrehan } 2013250199Sgrehan 2014250199Sgrehan mtx_lock(&sc->hs_lock); 2015250199Sgrehan if (reqp->softc->hs_frozen == 1) { 2016250199Sgrehan xpt_print(ccb->ccb_h.path, 2017250199Sgrehan "%u: storvsc unfreezing softc 0x%p.\n", 2018250199Sgrehan ticks, reqp->softc); 2019250199Sgrehan ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 2020250199Sgrehan reqp->softc->hs_frozen = 0; 2021250199Sgrehan } 2022250199Sgrehan storvsc_free_request(sc, reqp); 2023250199Sgrehan xpt_done(ccb); 2024250199Sgrehan mtx_unlock(&sc->hs_lock); 2025250199Sgrehan} 2026250199Sgrehan 2027250199Sgrehan/** 2028250199Sgrehan * @brief Free a request structure 2029250199Sgrehan * 2030250199Sgrehan * Free a request structure by returning it to the free list 2031250199Sgrehan * 2032250199Sgrehan * @param sc pointer to a softc 2033250199Sgrehan * @param reqp pointer to a request structure 2034250199Sgrehan */ 2035250199Sgrehanstatic void 2036250199Sgrehanstorvsc_free_request(struct storvsc_softc *sc, struct hv_storvsc_request *reqp) 2037250199Sgrehan{ 2038250199Sgrehan 2039250199Sgrehan LIST_INSERT_HEAD(&sc->hs_free_list, reqp, link); 2040250199Sgrehan} 2041250199Sgrehan 2042250199Sgrehan/** 2043250199Sgrehan * @brief Determine type of storage device from GUID 2044250199Sgrehan * 2045250199Sgrehan * Using the type GUID, determine if this is a StorVSC (paravirtual 2046250199Sgrehan * SCSI or BlkVSC (paravirtual IDE) device. 2047250199Sgrehan * 2048250199Sgrehan * @param dev a device 2049250199Sgrehan * returns an enum 2050250199Sgrehan */ 2051250199Sgrehanstatic enum hv_storage_type 2052250199Sgrehanstorvsc_get_storage_type(device_t dev) 2053250199Sgrehan{ 2054250199Sgrehan const char *p = vmbus_get_type(dev); 2055250199Sgrehan 2056250199Sgrehan if (!memcmp(p, &gBlkVscDeviceType, sizeof(hv_guid))) { 2057250199Sgrehan return DRIVER_BLKVSC; 2058250199Sgrehan } else if (!memcmp(p, &gStorVscDeviceType, sizeof(hv_guid))) { 2059250199Sgrehan return DRIVER_STORVSC; 2060250199Sgrehan } 2061250199Sgrehan return (DRIVER_UNKNOWN); 2062250199Sgrehan} 2063250199Sgrehan 2064