static int sbp2_send_management_orb()

in sbp2.c [547:643]


static int sbp2_send_management_orb(struct sbp2_logical_unit *lu, int node_id,
				    int generation, int function,
				    int lun_or_login_id, void *response)
{
	struct fw_device *device = target_parent_device(lu->tgt);
	struct sbp2_management_orb *orb;
	unsigned int timeout;
	int retval = -ENOMEM;

	if (function == SBP2_LOGOUT_REQUEST && fw_device_is_shutdown(device))
		return 0;

	orb = kzalloc(sizeof(*orb), GFP_NOIO);
	if (orb == NULL)
		return -ENOMEM;

	kref_init(&orb->base.kref);
	orb->response_bus =
		dma_map_single(device->card->device, &orb->response,
			       sizeof(orb->response), DMA_FROM_DEVICE);
	if (dma_mapping_error(device->card->device, orb->response_bus))
		goto fail_mapping_response;

	orb->request.response.high = 0;
	orb->request.response.low  = cpu_to_be32(orb->response_bus);

	orb->request.misc = cpu_to_be32(
		MANAGEMENT_ORB_NOTIFY |
		MANAGEMENT_ORB_FUNCTION(function) |
		MANAGEMENT_ORB_LUN(lun_or_login_id));
	orb->request.length = cpu_to_be32(
		MANAGEMENT_ORB_RESPONSE_LENGTH(sizeof(orb->response)));

	orb->request.status_fifo.high =
		cpu_to_be32(lu->address_handler.offset >> 32);
	orb->request.status_fifo.low  =
		cpu_to_be32(lu->address_handler.offset);

	if (function == SBP2_LOGIN_REQUEST) {
		/* Ask for 2^2 == 4 seconds reconnect grace period */
		orb->request.misc |= cpu_to_be32(
			MANAGEMENT_ORB_RECONNECT(2) |
			MANAGEMENT_ORB_EXCLUSIVE(sbp2_param_exclusive_login));
		timeout = lu->tgt->mgt_orb_timeout;
	} else {
		timeout = SBP2_ORB_TIMEOUT;
	}

	init_completion(&orb->done);
	orb->base.callback = complete_management_orb;

	orb->base.request_bus =
		dma_map_single(device->card->device, &orb->request,
			       sizeof(orb->request), DMA_TO_DEVICE);
	if (dma_mapping_error(device->card->device, orb->base.request_bus))
		goto fail_mapping_request;

	sbp2_send_orb(&orb->base, lu, node_id, generation,
		      lu->tgt->management_agent_address);

	wait_for_completion_timeout(&orb->done, msecs_to_jiffies(timeout));

	retval = -EIO;
	if (sbp2_cancel_orbs(lu) == 0) {
		dev_err(lu_dev(lu), "ORB reply timed out, rcode 0x%02x\n",
			orb->base.rcode);
		goto out;
	}

	if (orb->base.rcode != RCODE_COMPLETE) {
		dev_err(lu_dev(lu), "management write failed, rcode 0x%02x\n",
			orb->base.rcode);
		goto out;
	}

	if (STATUS_GET_RESPONSE(orb->status) != 0 ||
	    STATUS_GET_SBP_STATUS(orb->status) != 0) {
		dev_err(lu_dev(lu), "error status: %d:%d\n",
			 STATUS_GET_RESPONSE(orb->status),
			 STATUS_GET_SBP_STATUS(orb->status));
		goto out;
	}

	retval = 0;
 out:
	dma_unmap_single(device->card->device, orb->base.request_bus,
			 sizeof(orb->request), DMA_TO_DEVICE);
 fail_mapping_request:
	dma_unmap_single(device->card->device, orb->response_bus,
			 sizeof(orb->response), DMA_FROM_DEVICE);
 fail_mapping_response:
	if (response)
		memcpy(response, orb->response, sizeof(orb->response));
	kref_put(&orb->base.kref, free_orb);

	return retval;
}