00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 FILE_LICENCE ( GPL2_OR_LATER );
00020
00021 #include <stddef.h>
00022 #include <string.h>
00023 #include <stdio.h>
00024 #include <stdlib.h>
00025 #include <errno.h>
00026 #include <assert.h>
00027 #include <byteswap.h>
00028 #include <gpxe/list.h>
00029 #include <gpxe/if_ether.h>
00030 #include <gpxe/ethernet.h>
00031 #include <gpxe/iobuf.h>
00032 #include <gpxe/uaccess.h>
00033 #include <gpxe/ata.h>
00034 #include <gpxe/netdevice.h>
00035 #include <gpxe/process.h>
00036 #include <gpxe/features.h>
00037 #include <gpxe/aoe.h>
00038
00039
00040
00041
00042
00043
00044
00045 FEATURE ( FEATURE_PROTOCOL, "AoE", DHCP_EB_FEATURE_AOE, 1 );
00046
00047 struct net_protocol aoe_protocol;
00048
00049
00050 static LIST_HEAD ( aoe_sessions );
00051
00052 static void aoe_free ( struct refcnt *refcnt ) {
00053 struct aoe_session *aoe =
00054 container_of ( refcnt, struct aoe_session, refcnt );
00055
00056 netdev_put ( aoe->netdev );
00057 free ( aoe );
00058 }
00059
00060
00061
00062
00063
00064
00065
00066 static void aoe_done ( struct aoe_session *aoe, int rc ) {
00067
00068
00069 if ( aoe->command ) {
00070 aoe->command->cb.cmd_stat = aoe->status;
00071 aoe->command->rc = rc;
00072 aoe->command = NULL;
00073 }
00074
00075
00076 stop_timer ( &aoe->timer );
00077
00078
00079 aoe->rc = rc;
00080 }
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091 static int aoe_send_command ( struct aoe_session *aoe ) {
00092 struct ata_command *command = aoe->command;
00093 struct io_buffer *iobuf;
00094 struct aoehdr *aoehdr;
00095 union aoecmd *aoecmd;
00096 struct aoeata *aoeata;
00097 unsigned int count;
00098 unsigned int data_out_len;
00099 unsigned int aoecmdlen;
00100
00101
00102 if ( ! aoe->netdev ) {
00103 aoe_done ( aoe, -ENETUNREACH );
00104 return -ENETUNREACH;
00105 }
00106
00107
00108
00109
00110
00111
00112 start_timer ( &aoe->timer );
00113
00114
00115 switch ( aoe->aoe_cmd_type ) {
00116 case AOE_CMD_ATA:
00117 count = command->cb.count.native;
00118 if ( count > AOE_MAX_COUNT )
00119 count = AOE_MAX_COUNT;
00120 data_out_len = ( command->data_out ?
00121 ( count * ATA_SECTOR_SIZE ) : 0 );
00122 aoecmdlen = sizeof ( aoecmd->ata );
00123 break;
00124 case AOE_CMD_CONFIG:
00125 count = 0;
00126 data_out_len = 0;
00127 aoecmdlen = sizeof ( aoecmd->cfg );
00128 break;
00129 default:
00130 return -ENOTSUP;
00131 }
00132
00133
00134 iobuf = alloc_iob ( ETH_HLEN + sizeof ( *aoehdr ) +
00135 aoecmdlen + data_out_len );
00136
00137 if ( ! iobuf )
00138 return -ENOMEM;
00139 iob_reserve ( iobuf, ETH_HLEN );
00140 aoehdr = iob_put ( iobuf, sizeof ( *aoehdr ) );
00141 aoecmd = iob_put ( iobuf, aoecmdlen );
00142 memset ( aoehdr, 0, ( sizeof ( *aoehdr ) + aoecmdlen ) );
00143
00144
00145 aoehdr->ver_flags = AOE_VERSION;
00146 aoehdr->major = htons ( aoe->major );
00147 aoehdr->minor = aoe->minor;
00148 aoehdr->command = aoe->aoe_cmd_type;
00149 aoehdr->tag = htonl ( ++aoe->tag );
00150
00151
00152 switch ( aoe->aoe_cmd_type ) {
00153 case AOE_CMD_ATA:
00154
00155 aoeata = &aoecmd->ata;
00156 linker_assert ( AOE_FL_DEV_HEAD == ATA_DEV_SLAVE,
00157 __fix_ata_h__ );
00158 aoeata->aflags = ( ( command->cb.lba48 ? AOE_FL_EXTENDED : 0 )|
00159 ( command->cb.device & ATA_DEV_SLAVE ) |
00160 ( data_out_len ? AOE_FL_WRITE : 0 ) );
00161 aoeata->err_feat = command->cb.err_feat.bytes.cur;
00162 aoeata->count = count;
00163 aoeata->cmd_stat = command->cb.cmd_stat;
00164 aoeata->lba.u64 = cpu_to_le64 ( command->cb.lba.native );
00165 if ( ! command->cb.lba48 )
00166 aoeata->lba.bytes[3] |=
00167 ( command->cb.device & ATA_DEV_MASK );
00168
00169
00170 copy_from_user ( iob_put ( iobuf, data_out_len ),
00171 command->data_out, aoe->command_offset,
00172 data_out_len );
00173 break;
00174 case AOE_CMD_CONFIG:
00175
00176 break;
00177 default:
00178 assert ( 0 );
00179 }
00180
00181
00182 return net_tx ( iobuf, aoe->netdev, &aoe_protocol, aoe->target );
00183 }
00184
00185
00186
00187
00188
00189
00190
00191 static void aoe_timer_expired ( struct retry_timer *timer, int fail ) {
00192 struct aoe_session *aoe =
00193 container_of ( timer, struct aoe_session, timer );
00194
00195 if ( fail ) {
00196 aoe_done ( aoe, -ETIMEDOUT );
00197 } else {
00198 aoe_send_command ( aoe );
00199 }
00200 }
00201
00202
00203
00204
00205
00206
00207
00208
00209 static int aoe_rx_cfg ( struct aoe_session *aoe, const void *ll_source ) {
00210
00211
00212 memcpy ( aoe->target, ll_source, sizeof ( aoe->target ) );
00213 DBGC ( aoe, "AoE %p target MAC address %s\n",
00214 aoe, eth_ntoa ( aoe->target ) );
00215
00216
00217 aoe_done ( aoe, 0 );
00218
00219 return 0;
00220 }
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230 static int aoe_rx_ata ( struct aoe_session *aoe, struct aoeata *aoeata,
00231 size_t len ) {
00232 struct ata_command *command = aoe->command;
00233 unsigned int rx_data_len;
00234 unsigned int count;
00235 unsigned int data_len;
00236
00237
00238 if ( len < sizeof ( *aoeata ) ) {
00239
00240 return -EINVAL;
00241 }
00242 rx_data_len = ( len - sizeof ( *aoeata ) );
00243
00244
00245 count = command->cb.count.native;
00246 if ( count > AOE_MAX_COUNT )
00247 count = AOE_MAX_COUNT;
00248 data_len = count * ATA_SECTOR_SIZE;
00249
00250
00251 aoe->status |= aoeata->cmd_stat;
00252
00253
00254 if ( command->data_in ) {
00255 if ( rx_data_len > data_len )
00256 rx_data_len = data_len;
00257 copy_to_user ( command->data_in, aoe->command_offset,
00258 aoeata->data, rx_data_len );
00259 }
00260
00261
00262 aoe->command_offset += data_len;
00263 command->cb.lba.native += count;
00264 command->cb.count.native -= count;
00265
00266
00267 if ( ! command->cb.count.native ) {
00268 aoe_done ( aoe, 0 );
00269 return 0;
00270 }
00271
00272
00273 stop_timer ( &aoe->timer );
00274 aoe_send_command ( aoe );
00275
00276 return 0;
00277 }
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288 static int aoe_rx ( struct io_buffer *iobuf,
00289 struct net_device *netdev __unused,
00290 const void *ll_source ) {
00291 struct aoehdr *aoehdr = iobuf->data;
00292 struct aoe_session *aoe;
00293 int rc = 0;
00294
00295
00296 if ( iob_len ( iobuf ) < sizeof ( *aoehdr ) ) {
00297 rc = -EINVAL;
00298 goto done;
00299 }
00300 if ( ( aoehdr->ver_flags & AOE_VERSION_MASK ) != AOE_VERSION ) {
00301 rc = -EPROTONOSUPPORT;
00302 goto done;
00303 }
00304 if ( ! ( aoehdr->ver_flags & AOE_FL_RESPONSE ) ) {
00305
00306 goto done;
00307 }
00308 iob_pull ( iobuf, sizeof ( *aoehdr ) );
00309
00310
00311 list_for_each_entry ( aoe, &aoe_sessions, list ) {
00312 if ( ntohs ( aoehdr->major ) != aoe->major )
00313 continue;
00314 if ( aoehdr->minor != aoe->minor )
00315 continue;
00316 if ( ntohl ( aoehdr->tag ) != aoe->tag )
00317 continue;
00318 if ( aoehdr->ver_flags & AOE_FL_ERROR ) {
00319 aoe_done ( aoe, -EIO );
00320 break;
00321 }
00322 switch ( aoehdr->command ) {
00323 case AOE_CMD_ATA:
00324 rc = aoe_rx_ata ( aoe, iobuf->data, iob_len ( iobuf ));
00325 break;
00326 case AOE_CMD_CONFIG:
00327 rc = aoe_rx_cfg ( aoe, ll_source );
00328 break;
00329 default:
00330 DBGC ( aoe, "AoE %p ignoring command %02x\n",
00331 aoe, aoehdr->command );
00332 break;
00333 }
00334 break;
00335 }
00336
00337 done:
00338 free_iob ( iobuf );
00339 return rc;
00340 }
00341
00342
00343 struct net_protocol aoe_protocol __net_protocol = {
00344 .name = "AoE",
00345 .net_proto = htons ( ETH_P_AOE ),
00346 .rx = aoe_rx,
00347 };
00348
00349
00350
00351
00352
00353
00354
00355
00356 static int aoe_command ( struct ata_device *ata,
00357 struct ata_command *command ) {
00358 struct aoe_session *aoe =
00359 container_of ( ata->backend, struct aoe_session, refcnt );
00360
00361 aoe->command = command;
00362 aoe->status = 0;
00363 aoe->command_offset = 0;
00364 aoe->aoe_cmd_type = AOE_CMD_ATA;
00365
00366 aoe_send_command ( aoe );
00367
00368 return 0;
00369 }
00370
00371
00372
00373
00374
00375
00376
00377 static int aoe_discover ( struct aoe_session *aoe ) {
00378 int rc;
00379
00380 aoe->status = 0;
00381 aoe->aoe_cmd_type = AOE_CMD_CONFIG;
00382 aoe->command = NULL;
00383
00384 aoe_send_command ( aoe );
00385
00386 aoe->rc = -EINPROGRESS;
00387 while ( aoe->rc == -EINPROGRESS )
00388 step();
00389 rc = aoe->rc;
00390
00391 return rc;
00392 }
00393
00394 static int aoe_detached_command ( struct ata_device *ata __unused,
00395 struct ata_command *command __unused ) {
00396 return -ENODEV;
00397 }
00398
00399 void aoe_detach ( struct ata_device *ata ) {
00400 struct aoe_session *aoe =
00401 container_of ( ata->backend, struct aoe_session, refcnt );
00402
00403 stop_timer ( &aoe->timer );
00404 ata->command = aoe_detached_command;
00405 list_del ( &aoe->list );
00406 ref_put ( ata->backend );
00407 ata->backend = NULL;
00408 }
00409
00410 static int aoe_parse_root_path ( struct aoe_session *aoe,
00411 const char *root_path ) {
00412 char *ptr;
00413
00414 if ( strncmp ( root_path, "aoe:", 4 ) != 0 )
00415 return -EINVAL;
00416 ptr = ( ( char * ) root_path + 4 );
00417
00418 if ( *ptr++ != 'e' )
00419 return -EINVAL;
00420
00421 aoe->major = strtoul ( ptr, &ptr, 10 );
00422 if ( *ptr++ != '.' )
00423 return -EINVAL;
00424
00425 aoe->minor = strtoul ( ptr, &ptr, 10 );
00426 if ( *ptr )
00427 return -EINVAL;
00428
00429 return 0;
00430 }
00431
00432 int aoe_attach ( struct ata_device *ata, struct net_device *netdev,
00433 const char *root_path ) {
00434 struct aoe_session *aoe;
00435 int rc;
00436
00437
00438 aoe = zalloc ( sizeof ( *aoe ) );
00439 if ( ! aoe )
00440 return -ENOMEM;
00441 aoe->refcnt.free = aoe_free;
00442 aoe->netdev = netdev_get ( netdev );
00443 memcpy ( aoe->target, netdev->ll_broadcast, sizeof ( aoe->target ) );
00444 aoe->tag = AOE_TAG_MAGIC;
00445 aoe->timer.expired = aoe_timer_expired;
00446
00447
00448 if ( ( rc = aoe_parse_root_path ( aoe, root_path ) ) != 0 )
00449 goto err;
00450
00451
00452
00453
00454 ata->backend = ref_get ( &aoe->refcnt );
00455 ata->command = aoe_command;
00456 list_add ( &aoe->list, &aoe_sessions );
00457
00458
00459
00460
00461
00462
00463 if ( ( rc = aoe_discover( aoe ) ) != 0 )
00464 goto err;
00465
00466 return 0;
00467
00468 err:
00469 ref_put ( &aoe->refcnt );
00470 return rc;
00471 }