176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This program is free software; you can redistribute it and/or
576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * modify it under the terms of the GNU General Public License as
676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * published by the Free Software Foundation; either version 2 of the
776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * License, or any later version.
876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This program is distributed in the hope that it will be useful, but
1076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * WITHOUT ANY WARRANTY; without even the implied warranty of
1176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * General Public License for more details.
1376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
1476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * You should have received a copy of the GNU General Public License
1576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * along with this program; if not, write to the Free Software
1676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
1776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
1876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
1976d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanFILE_LICENCE ( GPL2_OR_LATER );
2076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
2176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stddef.h>
2276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <string.h>
2376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stdio.h>
2476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stdlib.h>
2576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <errno.h>
2676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <assert.h>
2776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <byteswap.h>
2876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/list.h>
2976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/if_ether.h>
3076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/ethernet.h>
3176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/iobuf.h>
3276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/uaccess.h>
3376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/ata.h>
3476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/netdevice.h>
3576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/process.h>
3676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/features.h>
3776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/aoe.h>
3876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
3976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** @file
4076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
4176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * AoE protocol
4276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
4376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
4476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
4576d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanFEATURE ( FEATURE_PROTOCOL, "AoE", DHCP_EB_FEATURE_AOE, 1 );
4676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
4776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct net_protocol aoe_protocol;
4876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
4976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** List of all AoE sessions */
5076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic LIST_HEAD ( aoe_sessions );
5176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
5276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void aoe_free ( struct refcnt *refcnt ) {
5376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct aoe_session *aoe =
5476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		container_of ( refcnt, struct aoe_session, refcnt );
5576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
5676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	netdev_put ( aoe->netdev );
5776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	free ( aoe );
5876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
5976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
6076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
6176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Mark current AoE command complete
6276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
6376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v aoe		AoE session
6476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v rc		Return status code
6576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
6676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void aoe_done ( struct aoe_session *aoe, int rc ) {
6776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
6876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Record overall command status */
6976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ( aoe->command ) {
7076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		aoe->command->cb.cmd_stat = aoe->status;
7176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		aoe->command->rc = rc;
7276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		aoe->command = NULL;
7376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
7476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
7576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Stop retransmission timer */
7676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	stop_timer ( &aoe->timer );
7776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
7876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Mark operation as complete */
7976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	aoe->rc = rc;
8076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
8176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
8276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
8376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Send AoE command
8476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
8576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v aoe		AoE session
8676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret rc		Return status code
8776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
8876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This transmits an AoE command packet.  It does not wait for a
8976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * response.
9076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
9176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int aoe_send_command ( struct aoe_session *aoe ) {
9276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct ata_command *command = aoe->command;
9376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct io_buffer *iobuf;
9476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct aoehdr *aoehdr;
9576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	union aoecmd *aoecmd;
9676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct aoeata *aoeata;
9776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	unsigned int count;
9876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	unsigned int data_out_len;
9976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	unsigned int aoecmdlen;
10076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
10176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Fail immediately if we have no netdev to send on */
10276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ( ! aoe->netdev ) {
10376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		aoe_done ( aoe, -ENETUNREACH );
10476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		return -ENETUNREACH;
10576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
10676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
10776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* If we are transmitting anything that requires a response,
10876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman         * start the retransmission timer.  Do this before attempting
10976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman         * to allocate the I/O buffer, in case allocation itself
11076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman         * fails.
11176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman         */
11276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	start_timer ( &aoe->timer );
11376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
11476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Calculate count and data_out_len for this subcommand */
11576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	switch ( aoe->aoe_cmd_type ) {
11676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case AOE_CMD_ATA:
11776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		count = command->cb.count.native;
11876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if ( count > AOE_MAX_COUNT )
11976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			count = AOE_MAX_COUNT;
12076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		data_out_len = ( command->data_out ?
12176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman				 ( count * ATA_SECTOR_SIZE ) : 0 );
12276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		aoecmdlen = sizeof ( aoecmd->ata );
12376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		break;
12476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case AOE_CMD_CONFIG:
12576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		count = 0;
12676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		data_out_len = 0;
12776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		aoecmdlen = sizeof ( aoecmd->cfg );
12876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		break;
12976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	default:
13076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		return -ENOTSUP;
13176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
13276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
13376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Create outgoing I/O buffer */
13476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	iobuf = alloc_iob ( ETH_HLEN + sizeof ( *aoehdr ) +
13576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			    aoecmdlen + data_out_len );
13676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
13776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ( ! iobuf )
13876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		return -ENOMEM;
13976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	iob_reserve ( iobuf, ETH_HLEN );
14076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	aoehdr = iob_put ( iobuf, sizeof ( *aoehdr ) );
14176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	aoecmd = iob_put ( iobuf, aoecmdlen );
14276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	memset ( aoehdr, 0, ( sizeof ( *aoehdr ) + aoecmdlen ) );
14376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
14476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Fill AoE header */
14576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	aoehdr->ver_flags = AOE_VERSION;
14676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	aoehdr->major = htons ( aoe->major );
14776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	aoehdr->minor = aoe->minor;
14876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	aoehdr->command = aoe->aoe_cmd_type;
14976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	aoehdr->tag = htonl ( ++aoe->tag );
15076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
15176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Fill AoE payload */
15276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	switch ( aoe->aoe_cmd_type ) {
15376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case AOE_CMD_ATA:
15476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		/* Fill AoE command */
15576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		aoeata = &aoecmd->ata;
15676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		linker_assert ( AOE_FL_DEV_HEAD	== ATA_DEV_SLAVE,
15776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman				__fix_ata_h__ );
15876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		aoeata->aflags = ( ( command->cb.lba48 ? AOE_FL_EXTENDED : 0 )|
15976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman				   ( command->cb.device & ATA_DEV_SLAVE ) |
16076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman				   ( data_out_len ? AOE_FL_WRITE : 0 ) );
16176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		aoeata->err_feat = command->cb.err_feat.bytes.cur;
16276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		aoeata->count = count;
16376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		aoeata->cmd_stat = command->cb.cmd_stat;
16476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		aoeata->lba.u64 = cpu_to_le64 ( command->cb.lba.native );
16576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if ( ! command->cb.lba48 )
16676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			aoeata->lba.bytes[3] |=
16776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman				( command->cb.device & ATA_DEV_MASK );
16876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
16976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		/* Fill data payload */
17076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		copy_from_user ( iob_put ( iobuf, data_out_len ),
17176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman				 command->data_out, aoe->command_offset,
17276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman				 data_out_len );
17376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		break;
17476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case AOE_CMD_CONFIG:
17576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		/* Nothing to do */
17676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		break;
17776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	default:
17876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		assert ( 0 );
17976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
18076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
18176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Send packet */
18276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return net_tx ( iobuf, aoe->netdev, &aoe_protocol, aoe->target );
18376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
18476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
18576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
18676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Handle AoE retry timer expiry
18776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
18876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v timer		AoE retry timer
18976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v fail		Failure indicator
19076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
19176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void aoe_timer_expired ( struct retry_timer *timer, int fail ) {
19276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct aoe_session *aoe =
19376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		container_of ( timer, struct aoe_session, timer );
19476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
19576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ( fail ) {
19676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		aoe_done ( aoe, -ETIMEDOUT );
19776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	} else {
19876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		aoe_send_command ( aoe );
19976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
20076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
20176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
20276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
20376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Handle AoE configuration command response
20476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
20576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v aoe		AoE session
20676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v ll_source		Link-layer source address
20776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret rc		Return status code
20876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
20976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int aoe_rx_cfg ( struct aoe_session *aoe, const void *ll_source ) {
21076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
21176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Record target MAC address */
21276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	memcpy ( aoe->target, ll_source, sizeof ( aoe->target ) );
21376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGC ( aoe, "AoE %p target MAC address %s\n",
21476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	       aoe, eth_ntoa ( aoe->target ) );
21576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
21676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Mark config request as complete */
21776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	aoe_done ( aoe, 0 );
21876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
21976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return 0;
22076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
22176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
22276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
22376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Handle AoE ATA command response
22476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
22576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v aoe		AoE session
22676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v aoeata		AoE ATA command
22776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v len		Length of AoE ATA command
22876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret rc		Return status code
22976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
23076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int aoe_rx_ata ( struct aoe_session *aoe, struct aoeata *aoeata,
23176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			size_t len ) {
23276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct ata_command *command = aoe->command;
23376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	unsigned int rx_data_len;
23476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	unsigned int count;
23576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	unsigned int data_len;
23676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
23776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Sanity check */
23876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ( len < sizeof ( *aoeata ) ) {
23976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		/* Ignore packet; allow timer to trigger retransmit */
24076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		return -EINVAL;
24176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
24276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rx_data_len = ( len - sizeof ( *aoeata ) );
24376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
24476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Calculate count and data_len for this subcommand */
24576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	count = command->cb.count.native;
24676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ( count > AOE_MAX_COUNT )
24776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		count = AOE_MAX_COUNT;
24876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	data_len = count * ATA_SECTOR_SIZE;
24976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
25076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Merge into overall ATA status */
25176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	aoe->status |= aoeata->cmd_stat;
25276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
25376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Copy data payload */
25476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ( command->data_in ) {
25576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if ( rx_data_len > data_len )
25676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			rx_data_len = data_len;
25776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		copy_to_user ( command->data_in, aoe->command_offset,
25876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			       aoeata->data, rx_data_len );
25976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
26076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
26176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Update ATA command and offset */
26276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	aoe->command_offset += data_len;
26376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	command->cb.lba.native += count;
26476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	command->cb.count.native -= count;
26576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
26676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Check for operation complete */
26776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ( ! command->cb.count.native ) {
26876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		aoe_done ( aoe, 0 );
26976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		return 0;
27076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
27176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
27276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Transmit next portion of request */
27376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	stop_timer ( &aoe->timer );
27476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	aoe_send_command ( aoe );
27576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
27676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return 0;
27776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
27876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
27976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
28076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Process incoming AoE packets
28176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
28276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v iobuf		I/O buffer
28376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v netdev		Network device
28476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v ll_source		Link-layer source address
28576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret rc		Return status code
28676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
28776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
28876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int aoe_rx ( struct io_buffer *iobuf,
28976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    struct net_device *netdev __unused,
29076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    const void *ll_source ) {
29176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct aoehdr *aoehdr = iobuf->data;
29276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct aoe_session *aoe;
29376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	int rc = 0;
29476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
29576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Sanity checks */
29676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ( iob_len ( iobuf ) < sizeof ( *aoehdr ) ) {
29776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rc = -EINVAL;
29876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		goto done;
29976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
30076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ( ( aoehdr->ver_flags & AOE_VERSION_MASK ) != AOE_VERSION ) {
30176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rc = -EPROTONOSUPPORT;
30276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		goto done;
30376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
30476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ( ! ( aoehdr->ver_flags & AOE_FL_RESPONSE ) ) {
30576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		/* Ignore AoE requests that we happen to see */
30676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		goto done;
30776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
30876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	iob_pull ( iobuf, sizeof ( *aoehdr ) );
30976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
31076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Demultiplex amongst active AoE sessions */
31176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	list_for_each_entry ( aoe, &aoe_sessions, list ) {
31276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if ( ntohs ( aoehdr->major ) != aoe->major )
31376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			continue;
31476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if ( aoehdr->minor != aoe->minor )
31576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			continue;
31676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if ( ntohl ( aoehdr->tag ) != aoe->tag )
31776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			continue;
31876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if ( aoehdr->ver_flags & AOE_FL_ERROR ) {
31976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			aoe_done ( aoe, -EIO );
32076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			break;
32176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		}
32276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		switch ( aoehdr->command ) {
32376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		case AOE_CMD_ATA:
32476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			rc = aoe_rx_ata ( aoe, iobuf->data, iob_len ( iobuf ));
32576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			break;
32676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		case AOE_CMD_CONFIG:
32776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			rc = aoe_rx_cfg ( aoe, ll_source );
32876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			break;
32976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		default:
33076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			DBGC ( aoe, "AoE %p ignoring command %02x\n",
33176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			       aoe, aoehdr->command );
33276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			break;
33376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		}
33476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		break;
33576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
33676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
33776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman done:
33876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	free_iob ( iobuf );
33976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return rc;
34076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
34176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
34276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** AoE protocol */
34376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct net_protocol aoe_protocol __net_protocol = {
34476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	.name = "AoE",
34576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	.net_proto = htons ( ETH_P_AOE ),
34676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	.rx = aoe_rx,
34776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman};
34876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
34976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
35076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Issue ATA command via an open AoE session
35176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
35276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v ata		ATA device
35376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v command		ATA command
35476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret rc		Return status code
35576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
35676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int aoe_command ( struct ata_device *ata,
35776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			 struct ata_command *command ) {
35876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct aoe_session *aoe =
35976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		container_of ( ata->backend, struct aoe_session, refcnt );
36076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
36176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	aoe->command = command;
36276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	aoe->status = 0;
36376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	aoe->command_offset = 0;
36476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	aoe->aoe_cmd_type = AOE_CMD_ATA;
36576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
36676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	aoe_send_command ( aoe );
36776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
36876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return 0;
36976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
37076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
37176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
37276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Issue AoE config query for AoE target discovery
37376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
37476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v aoe		AoE session
37576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret rc		Return status code
37676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
37776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int aoe_discover ( struct aoe_session *aoe ) {
37876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	int rc;
37976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
38076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	aoe->status = 0;
38176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	aoe->aoe_cmd_type = AOE_CMD_CONFIG;
38276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	aoe->command = NULL;
38376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
38476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	aoe_send_command ( aoe );
38576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
38676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	aoe->rc = -EINPROGRESS;
38776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	while ( aoe->rc == -EINPROGRESS )
38876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		step();
38976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rc = aoe->rc;
39076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
39176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return rc;
39276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
39376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
39476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int aoe_detached_command ( struct ata_device *ata __unused,
39576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman				  struct ata_command *command __unused ) {
39676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return -ENODEV;
39776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
39876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
39976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid aoe_detach ( struct ata_device *ata ) {
40076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct aoe_session *aoe =
40176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		container_of ( ata->backend, struct aoe_session, refcnt );
40276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
40376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	stop_timer ( &aoe->timer );
40476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	ata->command = aoe_detached_command;
40576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	list_del ( &aoe->list );
40676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	ref_put ( ata->backend );
40776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	ata->backend = NULL;
40876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
40976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
41076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int aoe_parse_root_path ( struct aoe_session *aoe,
41176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman				 const char *root_path ) {
41276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	char *ptr;
41376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
41476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ( strncmp ( root_path, "aoe:", 4 ) != 0 )
41576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		return -EINVAL;
41676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	ptr = ( ( char * ) root_path + 4 );
41776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
41876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ( *ptr++ != 'e' )
41976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		return -EINVAL;
42076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
42176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	aoe->major = strtoul ( ptr, &ptr, 10 );
42276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ( *ptr++ != '.' )
42376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		return -EINVAL;
42476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
42576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	aoe->minor = strtoul ( ptr, &ptr, 10 );
42676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ( *ptr )
42776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		return -EINVAL;
42876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
42976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return 0;
43076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
43176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
43276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint aoe_attach ( struct ata_device *ata, struct net_device *netdev,
43376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		 const char *root_path ) {
43476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct aoe_session *aoe;
43576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	int rc;
43676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
43776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Allocate and initialise structure */
43876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	aoe = zalloc ( sizeof ( *aoe ) );
43976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ( ! aoe )
44076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		return -ENOMEM;
44176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	aoe->refcnt.free = aoe_free;
44276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	aoe->netdev = netdev_get ( netdev );
44376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	memcpy ( aoe->target, netdev->ll_broadcast, sizeof ( aoe->target ) );
44476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	aoe->tag = AOE_TAG_MAGIC;
44576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	aoe->timer.expired = aoe_timer_expired;
44676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
44776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Parse root path */
44876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ( ( rc = aoe_parse_root_path ( aoe, root_path ) ) != 0 )
44976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		goto err;
45076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
45176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Attach parent interface, transfer reference to connection
45276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 * list, and return
45376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 */
45476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	ata->backend = ref_get ( &aoe->refcnt );
45576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	ata->command = aoe_command;
45676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	list_add ( &aoe->list, &aoe_sessions );
45776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
45876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Send discovery packet to find the target MAC address.
45976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 * Ideally, this ought to be done asynchronously, but the
46076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 * block device interface does not yet support asynchronous
46176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 * operation.
46276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 */
46376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ( ( rc = aoe_discover( aoe ) ) != 0 )
46476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	       goto err;
46576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
46676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return 0;
46776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
46876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman err:
46976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	ref_put ( &aoe->refcnt );
47076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return rc;
47176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
472