#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <assert.h>
#include <byteswap.h>
#include <gpxe/list.h>
#include <gpxe/if_ether.h>
#include <gpxe/ethernet.h>
#include <gpxe/iobuf.h>
#include <gpxe/uaccess.h>
#include <gpxe/ata.h>
#include <gpxe/netdevice.h>
#include <gpxe/process.h>
#include <gpxe/features.h>
#include <gpxe/aoe.h>
Go to the source code of this file.
Functions | |
| FILE_LICENCE (GPL2_OR_LATER) | |
| FEATURE (FEATURE_PROTOCOL,"AoE", DHCP_EB_FEATURE_AOE, 1) | |
| static | LIST_HEAD (aoe_sessions) |
| List of all AoE sessions. | |
| static void | aoe_free (struct refcnt *refcnt) |
| static void | aoe_done (struct aoe_session *aoe, int rc) |
| Mark current AoE command complete. | |
| static int | aoe_send_command (struct aoe_session *aoe) |
| Send AoE command. | |
| static void | aoe_timer_expired (struct retry_timer *timer, int fail) |
| Handle AoE retry timer expiry. | |
| static int | aoe_rx_cfg (struct aoe_session *aoe, const void *ll_source) |
| Handle AoE configuration command response. | |
| static int | aoe_rx_ata (struct aoe_session *aoe, struct aoeata *aoeata, size_t len) |
| Handle AoE ATA command response. | |
| static int | aoe_rx (struct io_buffer *iobuf, struct net_device *netdev __unused, const void *ll_source) |
| Process incoming AoE packets. | |
| static int | aoe_command (struct ata_device *ata, struct ata_command *command) |
| Issue ATA command via an open AoE session. | |
| static int | aoe_discover (struct aoe_session *aoe) |
| Issue AoE config query for AoE target discovery. | |
| static int | aoe_detached_command (struct ata_device *ata __unused, struct ata_command *command __unused) |
| void | aoe_detach (struct ata_device *ata) |
| static int | aoe_parse_root_path (struct aoe_session *aoe, const char *root_path) |
| int | aoe_attach (struct ata_device *ata, struct net_device *netdev, const char *root_path) |
Variables | |
| struct net_protocol | aoe_protocol |
| struct net_protocol aoe_protocol | __net_protocol |
| AoE protocol. | |
Definition in file aoe.c.
| FILE_LICENCE | ( | GPL2_OR_LATER | ) |
| FEATURE | ( | FEATURE_PROTOCOL | , | |
| "AoE" | , | |||
| DHCP_EB_FEATURE_AOE | , | |||
| 1 | ||||
| ) |
| static LIST_HEAD | ( | aoe_sessions | ) | [static] |
List of all AoE sessions.
| static void aoe_free | ( | struct refcnt * | refcnt | ) | [static] |
Definition at line 52 of file aoe.c.
References container_of, free(), aoe_session::netdev, and netdev_put().
Referenced by aoe_attach().
00052 { 00053 struct aoe_session *aoe = 00054 container_of ( refcnt, struct aoe_session, refcnt ); 00055 00056 netdev_put ( aoe->netdev ); 00057 free ( aoe ); 00058 }
| static void aoe_done | ( | struct aoe_session * | aoe, | |
| int | rc | |||
| ) | [static] |
Mark current AoE command complete.
| aoe | AoE session | |
| rc | Return status code |
Definition at line 66 of file aoe.c.
References ata_command::cb, ata_cb::cmd_stat, aoe_session::command, NULL, aoe_session::rc, ata_command::rc, aoe_session::status, stop_timer(), and aoe_session::timer.
Referenced by aoe_rx(), aoe_rx_ata(), aoe_rx_cfg(), aoe_send_command(), and aoe_timer_expired().
00066 { 00067 00068 /* Record overall command status */ 00069 if ( aoe->command ) { 00070 aoe->command->cb.cmd_stat = aoe->status; 00071 aoe->command->rc = rc; 00072 aoe->command = NULL; 00073 } 00074 00075 /* Stop retransmission timer */ 00076 stop_timer ( &aoe->timer ); 00077 00078 /* Mark operation as complete */ 00079 aoe->rc = rc; 00080 }
| static int aoe_send_command | ( | struct aoe_session * | aoe | ) | [static] |
Send AoE command.
| aoe | AoE session |
| rc | Return status code |
Definition at line 91 of file aoe.c.
References aoeata::aflags, alloc_iob(), AOE_CMD_ATA, AOE_CMD_CONFIG, aoe_session::aoe_cmd_type, aoe_done(), AOE_FL_DEV_HEAD, AOE_FL_EXTENDED, AOE_FL_WRITE, AOE_MAX_COUNT, aoe_protocol, AOE_VERSION, assert, aoecmd::ata, ATA_DEV_MASK, ATA_DEV_SLAVE, ATA_SECTOR_SIZE, aoeata::bytes, ata_fifo::bytes, ata_command::cb, aoecmd::cfg, ata_cb::cmd_stat, aoeata::cmd_stat, aoehdr::command, aoe_session::command, aoe_session::command_offset, copy_from_user(), ata_cb::count, aoeata::count, cpu_to_le64, ata_fifo::cur, ata_command::data_out, ata_cb::device, ENETUNREACH, ENOMEM, ENOTSUP, ata_cb::err_feat, aoeata::err_feat, ETH_HLEN, htonl, htons, iob_put, iob_reserve, ata_cb::lba, aoeata::lba, ata_cb::lba48, linker_assert, aoe_session::major, aoehdr::major, memset(), aoe_session::minor, aoehdr::minor, ata_lba::native, ata_fifo::native, net_tx(), aoe_session::netdev, start_timer(), aoe_session::tag, aoehdr::tag, aoe_session::target, aoe_session::timer, aoeata::u64, and aoehdr::ver_flags.
Referenced by aoe_command(), aoe_discover(), aoe_rx_ata(), and aoe_timer_expired().
00091 { 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 /* Fail immediately if we have no netdev to send on */ 00102 if ( ! aoe->netdev ) { 00103 aoe_done ( aoe, -ENETUNREACH ); 00104 return -ENETUNREACH; 00105 } 00106 00107 /* If we are transmitting anything that requires a response, 00108 * start the retransmission timer. Do this before attempting 00109 * to allocate the I/O buffer, in case allocation itself 00110 * fails. 00111 */ 00112 start_timer ( &aoe->timer ); 00113 00114 /* Calculate count and data_out_len for this subcommand */ 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 /* Create outgoing I/O buffer */ 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 /* Fill AoE header */ 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 /* Fill AoE payload */ 00152 switch ( aoe->aoe_cmd_type ) { 00153 case AOE_CMD_ATA: 00154 /* Fill AoE command */ 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 /* Fill data payload */ 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 /* Nothing to do */ 00176 break; 00177 default: 00178 assert ( 0 ); 00179 } 00180 00181 /* Send packet */ 00182 return net_tx ( iobuf, aoe->netdev, &aoe_protocol, aoe->target ); 00183 }
| static void aoe_timer_expired | ( | struct retry_timer * | timer, | |
| int | fail | |||
| ) | [static] |
Handle AoE retry timer expiry.
| timer | AoE retry timer | |
| fail | Failure indicator |
Definition at line 191 of file aoe.c.
References aoe_done(), aoe_send_command(), container_of, and ETIMEDOUT.
Referenced by aoe_attach().
00191 { 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 }
| static int aoe_rx_cfg | ( | struct aoe_session * | aoe, | |
| const void * | ll_source | |||
| ) | [static] |
Handle AoE configuration command response.
| aoe | AoE session | |
| ll_source | Link-layer source address |
| rc | Return status code |
Definition at line 209 of file aoe.c.
References aoe_done(), DBGC, eth_ntoa(), memcpy, and aoe_session::target.
Referenced by aoe_rx().
00209 { 00210 00211 /* Record target MAC address */ 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 /* Mark config request as complete */ 00217 aoe_done ( aoe, 0 ); 00218 00219 return 0; 00220 }
| static int aoe_rx_ata | ( | struct aoe_session * | aoe, | |
| struct aoeata * | aoeata, | |||
| size_t | len | |||
| ) | [static] |
Handle AoE ATA command response.
| rc | Return status code |
Definition at line 230 of file aoe.c.
References aoe_done(), AOE_MAX_COUNT, aoe_send_command(), ATA_SECTOR_SIZE, ata_command::cb, aoeata::cmd_stat, aoe_session::command, aoe_session::command_offset, copy_to_user(), ata_cb::count, aoeata::data, ata_command::data_in, EINVAL, ata_cb::lba, ata_lba::native, ata_fifo::native, aoe_session::status, stop_timer(), and aoe_session::timer.
Referenced by aoe_rx().
00231 { 00232 struct ata_command *command = aoe->command; 00233 unsigned int rx_data_len; 00234 unsigned int count; 00235 unsigned int data_len; 00236 00237 /* Sanity check */ 00238 if ( len < sizeof ( *aoeata ) ) { 00239 /* Ignore packet; allow timer to trigger retransmit */ 00240 return -EINVAL; 00241 } 00242 rx_data_len = ( len - sizeof ( *aoeata ) ); 00243 00244 /* Calculate count and data_len for this subcommand */ 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 /* Merge into overall ATA status */ 00251 aoe->status |= aoeata->cmd_stat; 00252 00253 /* Copy data payload */ 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 /* Update ATA command and offset */ 00262 aoe->command_offset += data_len; 00263 command->cb.lba.native += count; 00264 command->cb.count.native -= count; 00265 00266 /* Check for operation complete */ 00267 if ( ! command->cb.count.native ) { 00268 aoe_done ( aoe, 0 ); 00269 return 0; 00270 } 00271 00272 /* Transmit next portion of request */ 00273 stop_timer ( &aoe->timer ); 00274 aoe_send_command ( aoe ); 00275 00276 return 0; 00277 }
| static int aoe_rx | ( | struct io_buffer * | iobuf, | |
| struct net_device *netdev | __unused, | |||
| const void * | ll_source | |||
| ) | [static] |
Process incoming AoE packets.
| iobuf | I/O buffer | |
| netdev | Network device | |
| ll_source | Link-layer source address |
| rc | Return status code |
Definition at line 288 of file aoe.c.
References AOE_CMD_ATA, AOE_CMD_CONFIG, aoe_done(), AOE_FL_ERROR, AOE_FL_RESPONSE, aoe_rx_ata(), aoe_rx_cfg(), AOE_VERSION, AOE_VERSION_MASK, aoehdr::command, io_buffer::data, DBGC, EINVAL, EIO, EPROTONOSUPPORT, free_iob(), iob_len(), iob_pull, aoe_session::list, list_for_each_entry, aoe_session::major, aoehdr::major, aoe_session::minor, aoehdr::minor, ntohl, ntohs, aoe_session::rc, aoe_session::tag, aoehdr::tag, and aoehdr::ver_flags.
00290 { 00291 struct aoehdr *aoehdr = iobuf->data; 00292 struct aoe_session *aoe; 00293 int rc = 0; 00294 00295 /* Sanity checks */ 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 /* Ignore AoE requests that we happen to see */ 00306 goto done; 00307 } 00308 iob_pull ( iobuf, sizeof ( *aoehdr ) ); 00309 00310 /* Demultiplex amongst active AoE sessions */ 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 }
| static int aoe_command | ( | struct ata_device * | ata, | |
| struct ata_command * | command | |||
| ) | [static] |
Issue ATA command via an open AoE session.
| rc | Return status code |
Definition at line 356 of file aoe.c.
References AOE_CMD_ATA, aoe_session::aoe_cmd_type, aoe_send_command(), ata_device::backend, aoe_session::command, aoe_session::command_offset, container_of, and aoe_session::status.
Referenced by aoe_attach().
00357 { 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 }
| static int aoe_discover | ( | struct aoe_session * | aoe | ) | [static] |
Issue AoE config query for AoE target discovery.
| aoe | AoE session |
| rc | Return status code |
Definition at line 377 of file aoe.c.
References AOE_CMD_CONFIG, aoe_session::aoe_cmd_type, aoe_send_command(), aoe_session::command, EINPROGRESS, NULL, aoe_session::rc, aoe_session::status, and step().
Referenced by aoe_attach().
00377 { 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 }
| static int aoe_detached_command | ( | struct ata_device *ata | __unused, | |
| struct ata_command *command | __unused | |||
| ) | [static] |
Definition at line 394 of file aoe.c.
References ENODEV.
Referenced by aoe_detach().
00395 { 00396 return -ENODEV; 00397 }
| void aoe_detach | ( | struct ata_device * | ata | ) |
Definition at line 399 of file aoe.c.
References aoe_detached_command(), ata_device::backend, ata_device::command, container_of, aoe_session::list, list_del, NULL, ref_put(), stop_timer(), and aoe_session::timer.
Referenced by aoeboot().
00399 { 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 }
| static int aoe_parse_root_path | ( | struct aoe_session * | aoe, | |
| const char * | root_path | |||
| ) | [static] |
Definition at line 410 of file aoe.c.
References EINVAL, aoe_session::major, aoe_session::minor, strncmp(), and strtoul().
Referenced by aoe_attach().
00411 { 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 }
| int aoe_attach | ( | struct ata_device * | ata, | |
| struct net_device * | netdev, | |||
| const char * | root_path | |||
| ) |
Definition at line 432 of file aoe.c.
References aoe_command(), aoe_discover(), aoe_free(), aoe_parse_root_path(), AOE_TAG_MAGIC, aoe_timer_expired(), ata_device::backend, ata_device::command, ENOMEM, retry_timer::expired, refcnt::free, aoe_session::list, list_add, net_device::ll_broadcast, memcpy, aoe_session::netdev, netdev_get(), aoe_session::rc, ref_get(), ref_put(), aoe_session::refcnt, aoe_session::tag, aoe_session::target, aoe_session::timer, and zalloc().
Referenced by aoeboot().
00433 { 00434 struct aoe_session *aoe; 00435 int rc; 00436 00437 /* Allocate and initialise structure */ 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 /* Parse root path */ 00448 if ( ( rc = aoe_parse_root_path ( aoe, root_path ) ) != 0 ) 00449 goto err; 00450 00451 /* Attach parent interface, transfer reference to connection 00452 * list, and return 00453 */ 00454 ata->backend = ref_get ( &aoe->refcnt ); 00455 ata->command = aoe_command; 00456 list_add ( &aoe->list, &aoe_sessions ); 00457 00458 /* Send discovery packet to find the target MAC address. 00459 * Ideally, this ought to be done asynchronously, but the 00460 * block device interface does not yet support asynchronous 00461 * operation. 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 }
| struct net_protocol aoe_protocol |
1.5.7.1