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