Changeset View
Standalone View
sys/dev/hyperv/storvsc/hv_storvsc_drv_freebsd.c
| Show First 20 Lines • Show All 116 Lines • ▼ Show 20 Lines | struct hv_storvsc_request { | ||||
| struct vstor_packet vstor_packet; | struct vstor_packet vstor_packet; | ||||
| hv_vmbus_multipage_buffer data_buf; | hv_vmbus_multipage_buffer data_buf; | ||||
| void *sense_data; | void *sense_data; | ||||
| uint8_t sense_info_len; | uint8_t sense_info_len; | ||||
| uint8_t retries; | uint8_t retries; | ||||
| union ccb *ccb; | union ccb *ccb; | ||||
| struct storvsc_softc *softc; | struct storvsc_softc *softc; | ||||
| struct callout callout; | struct callout callout; | ||||
| struct sema synch_sema; /*Synchronize the request/response if needed */ | |||||
| struct sglist *bounce_sgl; | struct sglist *bounce_sgl; | ||||
| unsigned int bounce_sgl_count; | unsigned int bounce_sgl_count; | ||||
| uint64_t not_aligned_seg_bits; | uint64_t not_aligned_seg_bits; | ||||
| }; | }; | ||||
| struct storvsc_softc { | struct storvsc_softc { | ||||
| struct hv_device *hs_dev; | struct hv_device *hs_dev; | ||||
| LIST_HEAD(, hv_storvsc_request) hs_free_list; | LIST_HEAD(, hv_storvsc_request) hs_free_list; | ||||
| ▲ Show 20 Lines • Show All 248 Lines • ▼ Show 20 Lines | storvsc_send_multichannel_request(struct hv_device *dev, int max_chans) | ||||
| request = &sc->hs_init_req; | request = &sc->hs_init_req; | ||||
| /* Establish a handler for multi-channel */ | /* Establish a handler for multi-channel */ | ||||
| dev->channel->sc_creation_callback = storvsc_handle_sc_creation; | dev->channel->sc_creation_callback = storvsc_handle_sc_creation; | ||||
| /* request the host to create multi-channel */ | /* request the host to create multi-channel */ | ||||
| memset(request, 0, sizeof(struct hv_storvsc_request)); | memset(request, 0, sizeof(struct hv_storvsc_request)); | ||||
| sema_init(&request->synch_sema, 0, ("stor_synch_sema")); | |||||
| vstor_packet = &request->vstor_packet; | vstor_packet = &request->vstor_packet; | ||||
| vstor_packet->operation = VSTOR_OPERATION_CREATE_MULTI_CHANNELS; | vstor_packet->operation = VSTOR_OPERATION_CREATE_MULTI_CHANNELS; | ||||
| vstor_packet->flags = REQUEST_COMPLETION_FLAG; | vstor_packet->flags = REQUEST_COMPLETION_FLAG; | ||||
| vstor_packet->u.multi_channels_cnt = request_channels_cnt; | vstor_packet->u.multi_channels_cnt = request_channels_cnt; | ||||
| ret = hv_vmbus_channel_send_packet( | ret = hv_vmbus_channel_send_packet( | ||||
| dev->channel, | dev->channel, | ||||
| vstor_packet, | vstor_packet, | ||||
| VSTOR_PKT_SIZE, | VSTOR_PKT_SIZE, | ||||
| (uint64_t)(uintptr_t)request, | (uint64_t)(uintptr_t)request, | ||||
| HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, | HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, | ||||
| HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); | HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); | ||||
| /* wait for 5 seconds */ | /* wait for 5 seconds */ | ||||
| ret = sema_timedwait(&request->synch_sema, 5 * hz); | ret = msleep(request, &sc->hs_lock, PRIBIO, "CINIT", 5 * hz); | ||||
| if (ret != 0) { | if (ret != 0) { | ||||
| printf("Storvsc_error: create multi-channel timeout, %d\n", | printf("Storvsc_error: create multi-channel timeout, %d\n", | ||||
| ret); | ret); | ||||
| return; | return; | ||||
| } | } | ||||
| if (vstor_packet->operation != VSTOR_OPERATION_COMPLETEIO || | if (vstor_packet->operation != VSTOR_OPERATION_COMPLETEIO || | ||||
| vstor_packet->status != 0) { | vstor_packet->status != 0) { | ||||
| printf("Storvsc_error: create multi-channel invalid operation " | printf("Storvsc_error: create multi-channel invalid operation " | ||||
| Show All 31 Lines | hv_storvsc_channel_init(struct hv_device *dev) | ||||
| if (sc == NULL) | if (sc == NULL) | ||||
| return (ENODEV); | return (ENODEV); | ||||
| request = &sc->hs_init_req; | request = &sc->hs_init_req; | ||||
| memset(request, 0, sizeof(struct hv_storvsc_request)); | memset(request, 0, sizeof(struct hv_storvsc_request)); | ||||
| vstor_packet = &request->vstor_packet; | vstor_packet = &request->vstor_packet; | ||||
| request->softc = sc; | request->softc = sc; | ||||
| /** | |||||
| * Initiate the vsc/vsp initialization protocol on the open channel | |||||
| */ | |||||
| sema_init(&request->synch_sema, 0, ("stor_synch_sema")); | |||||
| vstor_packet->operation = VSTOR_OPERATION_BEGININITIALIZATION; | vstor_packet->operation = VSTOR_OPERATION_BEGININITIALIZATION; | ||||
| vstor_packet->flags = REQUEST_COMPLETION_FLAG; | vstor_packet->flags = REQUEST_COMPLETION_FLAG; | ||||
| ret = hv_vmbus_channel_send_packet( | ret = hv_vmbus_channel_send_packet( | ||||
| dev->channel, | dev->channel, | ||||
| vstor_packet, | vstor_packet, | ||||
| VSTOR_PKT_SIZE, | VSTOR_PKT_SIZE, | ||||
| (uint64_t)(uintptr_t)request, | (uint64_t)(uintptr_t)request, | ||||
| HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, | HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, | ||||
| HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); | HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); | ||||
| if (ret != 0) | if (ret != 0) | ||||
| goto cleanup; | goto cleanup; | ||||
| /* wait 5 seconds */ | /* wait 5 seconds */ | ||||
| ret = sema_timedwait(&request->synch_sema, 5 * hz); | ret = msleep(request, &sc->hs_lock, PRIBIO, "CINIT", 5 * hz); | ||||
| if (ret != 0) | if (ret != 0) | ||||
| goto cleanup; | goto cleanup; | ||||
| if (vstor_packet->operation != VSTOR_OPERATION_COMPLETEIO || | if (vstor_packet->operation != VSTOR_OPERATION_COMPLETEIO || | ||||
| vstor_packet->status != 0) { | vstor_packet->status != 0) { | ||||
| goto cleanup; | goto cleanup; | ||||
| } | } | ||||
| Show All 16 Lines | ret = hv_vmbus_channel_send_packet( | ||||
| (uint64_t)(uintptr_t)request, | (uint64_t)(uintptr_t)request, | ||||
| HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, | HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, | ||||
| HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); | HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); | ||||
| if (ret != 0) | if (ret != 0) | ||||
| goto cleanup; | goto cleanup; | ||||
| /* wait 5 seconds */ | /* wait 5 seconds */ | ||||
| ret = sema_timedwait(&request->synch_sema, 5 * hz); | ret = msleep(request, &sc->hs_lock, PRIBIO, "CINIT", 5 * hz); | ||||
| if (ret) | if (ret) | ||||
| goto cleanup; | goto cleanup; | ||||
| /* TODO: Check returned version */ | /* TODO: Check returned version */ | ||||
| if (vstor_packet->operation != VSTOR_OPERATION_COMPLETEIO || | if (vstor_packet->operation != VSTOR_OPERATION_COMPLETEIO || | ||||
| vstor_packet->status != 0) | vstor_packet->status != 0) | ||||
| goto cleanup; | goto cleanup; | ||||
| Show All 12 Lines | ret = hv_vmbus_channel_send_packet( | ||||
| (uint64_t)(uintptr_t)request, | (uint64_t)(uintptr_t)request, | ||||
| HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, | HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, | ||||
| HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); | HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); | ||||
| if ( ret != 0) | if ( ret != 0) | ||||
| goto cleanup; | goto cleanup; | ||||
| /* wait 5 seconds */ | /* wait 5 seconds */ | ||||
| ret = sema_timedwait(&request->synch_sema, 5 * hz); | ret = msleep(request, &sc->hs_lock, PRIBIO, "CINIT", 5 * hz); | ||||
| if (ret != 0) | if (ret != 0) | ||||
| goto cleanup; | goto cleanup; | ||||
| /* TODO: Check returned version */ | /* TODO: Check returned version */ | ||||
| if (vstor_packet->operation != VSTOR_OPERATION_COMPLETEIO || | if (vstor_packet->operation != VSTOR_OPERATION_COMPLETEIO || | ||||
| vstor_packet->status != 0) { | vstor_packet->status != 0) { | ||||
| goto cleanup; | goto cleanup; | ||||
| Show All 20 Lines | ret = hv_vmbus_channel_send_packet( | ||||
| HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, | HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, | ||||
| HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); | HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); | ||||
| if (ret != 0) { | if (ret != 0) { | ||||
| goto cleanup; | goto cleanup; | ||||
| } | } | ||||
| /* wait 5 seconds */ | /* wait 5 seconds */ | ||||
| ret = sema_timedwait(&request->synch_sema, 5 * hz); | ret = msleep(request, &sc->hs_lock, PRIBIO, "CINIT", 5 * hz); | ||||
| if (ret != 0) | if (ret != 0) | ||||
| goto cleanup; | goto cleanup; | ||||
| if (vstor_packet->operation != VSTOR_OPERATION_COMPLETEIO || | if (vstor_packet->operation != VSTOR_OPERATION_COMPLETEIO || | ||||
| vstor_packet->status != 0) | vstor_packet->status != 0) | ||||
| goto cleanup; | goto cleanup; | ||||
| /* | /* | ||||
| * If multi-channel is supported, send multichannel create | * If multi-channel is supported, send multichannel create | ||||
| * request to host. | * request to host. | ||||
| */ | */ | ||||
| if (support_multichannel) | if (support_multichannel) | ||||
| storvsc_send_multichannel_request(dev, max_chans); | storvsc_send_multichannel_request(dev, max_chans); | ||||
| cleanup: | cleanup: | ||||
| sema_destroy(&request->synch_sema); | |||||
| return (ret); | return (ret); | ||||
| } | } | ||||
| /** | /** | ||||
| * @brief Open channel connection to paraent partition StorVSP driver | * @brief Open channel connection to paraent partition StorVSP driver | ||||
| * | * | ||||
| * Open and initialize channel connection to parent partition StorVSP driver. | * Open and initialize channel connection to parent partition StorVSP driver. | ||||
| * | * | ||||
| Show All 23 Lines | ret = hv_vmbus_channel_open( | ||||
| sizeof(struct vmstor_chan_props), | sizeof(struct vmstor_chan_props), | ||||
| hv_storvsc_on_channel_callback, | hv_storvsc_on_channel_callback, | ||||
| dev->channel); | dev->channel); | ||||
| if (ret != 0) { | if (ret != 0) { | ||||
| return ret; | return ret; | ||||
| } | } | ||||
| mtx_lock(&sc->hs_lock); | |||||
honzhan_microsoft.com: Which resource need to be protected by this lock? | |||||
decui_microsoft.comUnsubmitted Not Done Inline ActionsIt's to make the msleep() usages work. decui_microsoft.com: It's to make the msleep() usages work.
msleep(xxx, &sc->hslock, xxx,...) assumes the lock has… | |||||
decui_microsoft.comUnsubmitted Not Done Inline Actionstypo.. "required" -> "acquired". decui_microsoft.com: typo.. "required" -> "acquired". | |||||
howard0su_gmail.comAuthorUnsubmitted Not Done Inline ActionsYes. This is due to avoid race condition between sleep and wakeup. In our case, it is not possible but WITNESS requires it anyhow. howard0su_gmail.com: Yes. This is due to avoid race condition between sleep and wakeup. In our case, it is not… | |||||
| ret = hv_storvsc_channel_init(dev); | ret = hv_storvsc_channel_init(dev); | ||||
| mtx_unlock(&sc->hs_lock); | |||||
| return (ret); | return (ret); | ||||
| } | } | ||||
| #if HVS_HOST_RESET | #if HVS_HOST_RESET | ||||
| static int | static int | ||||
| hv_storvsc_host_reset(struct hv_device *dev) | hv_storvsc_host_reset(struct hv_device *dev) | ||||
| { | { | ||||
| int ret = 0; | int ret = 0; | ||||
| struct storvsc_softc *sc; | struct storvsc_softc *sc; | ||||
| struct hv_storvsc_request *request; | struct hv_storvsc_request *request; | ||||
| struct vstor_packet *vstor_packet; | struct vstor_packet *vstor_packet; | ||||
| sc = get_stor_device(dev, TRUE); | sc = get_stor_device(dev, TRUE); | ||||
| if (sc == NULL) { | if (sc == NULL) { | ||||
| return ENODEV; | return ENODEV; | ||||
| } | } | ||||
| request = &sc->hs_reset_req; | request = &sc->hs_reset_req; | ||||
| request->softc = sc; | request->softc = sc; | ||||
| vstor_packet = &request->vstor_packet; | vstor_packet = &request->vstor_packet; | ||||
| sema_init(&request->synch_sema, 0, "stor synch sema"); | |||||
| vstor_packet->operation = VSTOR_OPERATION_RESETBUS; | vstor_packet->operation = VSTOR_OPERATION_RESETBUS; | ||||
| vstor_packet->flags = REQUEST_COMPLETION_FLAG; | vstor_packet->flags = REQUEST_COMPLETION_FLAG; | ||||
| ret = hv_vmbus_channel_send_packet(dev->channel, | ret = hv_vmbus_channel_send_packet(dev->channel, | ||||
| vstor_packet, | vstor_packet, | ||||
| VSTOR_PKT_SIZE, | VSTOR_PKT_SIZE, | ||||
| (uint64_t)(uintptr_t)&sc->hs_reset_req, | (uint64_t)(uintptr_t)&sc->hs_reset_req, | ||||
| HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, | HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, | ||||
| HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); | HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); | ||||
| if (ret != 0) { | if (ret != 0) { | ||||
| goto cleanup; | goto cleanup; | ||||
| } | } | ||||
| ret = sema_timedwait(&request->synch_sema, 5 * hz); /* KYS 5 seconds */ | ret = msleep(request, &sc->hs_lock, PRIBIO, "CINIT", 5 * hz); | ||||
| if (ret) { | if (ret) { | ||||
| goto cleanup; | goto cleanup; | ||||
| } | } | ||||
| /* | /* | ||||
| * At this point, all outstanding requests in the adapter | * At this point, all outstanding requests in the adapter | ||||
| * should have been flushed out and return to us | * should have been flushed out and return to us | ||||
| */ | */ | ||||
| cleanup: | cleanup: | ||||
| sema_destroy(&request->synch_sema); | |||||
| return (ret); | return (ret); | ||||
| } | } | ||||
| #endif /* HVS_HOST_RESET */ | #endif /* HVS_HOST_RESET */ | ||||
| /** | /** | ||||
| * @brief Function to initiate an I/O request | * @brief Function to initiate an I/O request | ||||
| * | * | ||||
| * @param device Hyper-V device pointer | * @param device Hyper-V device pointer | ||||
| ▲ Show 20 Lines • Show All 159 Lines • ▼ Show 20 Lines | hv_storvsc_on_channel_callback(void *context) | ||||
| while ((ret == 0) && (bytes_recvd > 0)) { | while ((ret == 0) && (bytes_recvd > 0)) { | ||||
| request = (struct hv_storvsc_request *)(uintptr_t)request_id; | request = (struct hv_storvsc_request *)(uintptr_t)request_id; | ||||
| if ((request == &sc->hs_init_req) || | if ((request == &sc->hs_init_req) || | ||||
| (request == &sc->hs_reset_req)) { | (request == &sc->hs_reset_req)) { | ||||
| memcpy(&request->vstor_packet, packet, | memcpy(&request->vstor_packet, packet, | ||||
| sizeof(struct vstor_packet)); | sizeof(struct vstor_packet)); | ||||
| sema_post(&request->synch_sema); | wakeup(request); | ||||
| } else { | } else { | ||||
| vstor_packet = (struct vstor_packet *)packet; | vstor_packet = (struct vstor_packet *)packet; | ||||
| switch(vstor_packet->operation) { | switch(vstor_packet->operation) { | ||||
| case VSTOR_OPERATION_COMPLETEIO: | case VSTOR_OPERATION_COMPLETEIO: | ||||
| if (request == NULL) | if (request == NULL) | ||||
| panic("VMBUS: storvsc received a " | panic("VMBUS: storvsc received a " | ||||
| "packet with NULL request id in " | "packet with NULL request id in " | ||||
| "COMPLETEIO operation."); | "COMPLETEIO operation."); | ||||
| ▲ Show 20 Lines • Show All 126 Lines • ▼ Show 20 Lines | storvsc_attach(device_t dev) | ||||
| sc->hs_dev = hv_dev; | sc->hs_dev = hv_dev; | ||||
| device_set_desc(dev, g_drv_props_table[stor_type].drv_desc); | device_set_desc(dev, g_drv_props_table[stor_type].drv_desc); | ||||
| LIST_INIT(&sc->hs_free_list); | LIST_INIT(&sc->hs_free_list); | ||||
| mtx_init(&sc->hs_lock, "hvslck", NULL, MTX_DEF); | mtx_init(&sc->hs_lock, "hvslck", NULL, MTX_DEF); | ||||
| for (i = 0; i < sc->hs_drv_props->drv_max_ios_per_target; ++i) { | for (i = 0; i < sc->hs_drv_props->drv_max_ios_per_target; ++i) { | ||||
| reqp = malloc(sizeof(struct hv_storvsc_request), | reqp = malloc(sizeof(struct hv_storvsc_request), | ||||
| M_DEVBUF, M_WAITOK|M_ZERO); | M_DEVBUF, M_WAITOK); | ||||
decui_microsoft.comUnsubmitted Not Done Inline ActionsI assume you've checked it's OK to remove the M_ZERO. However, I found the "retries" field of hv_storvsc_request may be used before proper initialization: grep 'retries = ' dev/hyperv/storvsc/ -nrdev/hyperv/storvsc/hv_storvsc_drv_freebsd.c:2027: reqp->retries = 0; We can see it's only initialized once in storvsc_io_done(), but in this function, it's also tested before the initialization. decui_microsoft.com: I assume you've checked it's OK to remove the M_ZERO.
However, I found the "retries" field of… | |||||
howard0su_gmail.comAuthorUnsubmitted Not Done Inline ActionsThis is actual a pre-allocate buf pool. every time, grab one from the pool, we will call bzero to initialize it. so it is not needed to zero it here. howard0su_gmail.com: This is actual a pre-allocate buf pool. every time, grab one from the pool, we will call bzero… | |||||
decui_microsoft.comUnsubmitted Not Done Inline ActionsGot it -- I saw that in storvsc_action()'s case XPT_SCSI_IO. decui_microsoft.com: Got it -- I saw that in storvsc_action()'s case XPT_SCSI_IO. | |||||
| reqp->softc = sc; | |||||
decui_microsoft.comUnsubmitted Not Done Inline ActionsWhy is it removed? reqp->softc is used in several places. decui_microsoft.com: Why is it removed? reqp->softc is used in several places. | |||||
howard0su_gmail.comAuthorUnsubmitted Not Done Inline Actionsit will bzero when grab it from the pool. and set softc again. howard0su_gmail.com: it will bzero when grab it from the pool. and set softc again. | |||||
decui_microsoft.comUnsubmitted Not Done Inline ActionsGot it. decui_microsoft.com: Got it. | |||||
| LIST_INSERT_HEAD(&sc->hs_free_list, reqp, link); | LIST_INSERT_HEAD(&sc->hs_free_list, reqp, link); | ||||
| } | } | ||||
| /* create sg-list page pool */ | /* create sg-list page pool */ | ||||
| if (FALSE == g_hv_sgl_page_pool.is_init) { | if (FALSE == g_hv_sgl_page_pool.is_init) { | ||||
| g_hv_sgl_page_pool.is_init = TRUE; | g_hv_sgl_page_pool.is_init = TRUE; | ||||
| LIST_INIT(&g_hv_sgl_page_pool.in_use_sgl_list); | LIST_INIT(&g_hv_sgl_page_pool.in_use_sgl_list); | ||||
| ▲ Show 20 Lines • Show All 1,122 Lines • Show Last 20 Lines | |||||
Which resource need to be protected by this lock?