1 /* 2 * Copyright (C) 2006 Michael Brown <mbrown (at) fensystems.co.uk>. 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License as 6 * published by the Free Software Foundation; either version 2 of the 7 * License, or any later version. 8 * 9 * This program is distributed in the hope that it will be useful, but 10 * WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 */ 18 19 FILE_LICENCE ( GPL2_OR_LATER ); 20 21 #include <stddef.h> 22 #include <string.h> 23 #include <stdio.h> 24 #include <stdlib.h> 25 #include <errno.h> 26 #include <assert.h> 27 #include <byteswap.h> 28 #include <gpxe/list.h> 29 #include <gpxe/if_ether.h> 30 #include <gpxe/ethernet.h> 31 #include <gpxe/iobuf.h> 32 #include <gpxe/uaccess.h> 33 #include <gpxe/ata.h> 34 #include <gpxe/netdevice.h> 35 #include <gpxe/process.h> 36 #include <gpxe/features.h> 37 #include <gpxe/aoe.h> 38 39 /** @file 40 * 41 * AoE protocol 42 * 43 */ 44 45 FEATURE ( FEATURE_PROTOCOL, "AoE", DHCP_EB_FEATURE_AOE, 1 ); 46 47 struct net_protocol aoe_protocol; 48 49 /** List of all AoE sessions */ 50 static LIST_HEAD ( aoe_sessions ); 51 52 static void aoe_free ( struct refcnt *refcnt ) { 53 struct aoe_session *aoe = 54 container_of ( refcnt, struct aoe_session, refcnt ); 55 56 netdev_put ( aoe->netdev ); 57 free ( aoe ); 58 } 59 60 /** 61 * Mark current AoE command complete 62 * 63 * @v aoe AoE session 64 * @v rc Return status code 65 */ 66 static void aoe_done ( struct aoe_session *aoe, int rc ) { 67 68 /* Record overall command status */ 69 if ( aoe->command ) { 70 aoe->command->cb.cmd_stat = aoe->status; 71 aoe->command->rc = rc; 72 aoe->command = NULL; 73 } 74 75 /* Stop retransmission timer */ 76 stop_timer ( &aoe->timer ); 77 78 /* Mark operation as complete */ 79 aoe->rc = rc; 80 } 81 82 /** 83 * Send AoE command 84 * 85 * @v aoe AoE session 86 * @ret rc Return status code 87 * 88 * This transmits an AoE command packet. It does not wait for a 89 * response. 90 */ 91 static int aoe_send_command ( struct aoe_session *aoe ) { 92 struct ata_command *command = aoe->command; 93 struct io_buffer *iobuf; 94 struct aoehdr *aoehdr; 95 union aoecmd *aoecmd; 96 struct aoeata *aoeata; 97 unsigned int count; 98 unsigned int data_out_len; 99 unsigned int aoecmdlen; 100 101 /* Fail immediately if we have no netdev to send on */ 102 if ( ! aoe->netdev ) { 103 aoe_done ( aoe, -ENETUNREACH ); 104 return -ENETUNREACH; 105 } 106 107 /* If we are transmitting anything that requires a response, 108 * start the retransmission timer. Do this before attempting 109 * to allocate the I/O buffer, in case allocation itself 110 * fails. 111 */ 112 start_timer ( &aoe->timer ); 113 114 /* Calculate count and data_out_len for this subcommand */ 115 switch ( aoe->aoe_cmd_type ) { 116 case AOE_CMD_ATA: 117 count = command->cb.count.native; 118 if ( count > AOE_MAX_COUNT ) 119 count = AOE_MAX_COUNT; 120 data_out_len = ( command->data_out ? 121 ( count * ATA_SECTOR_SIZE ) : 0 ); 122 aoecmdlen = sizeof ( aoecmd->ata ); 123 break; 124 case AOE_CMD_CONFIG: 125 count = 0; 126 data_out_len = 0; 127 aoecmdlen = sizeof ( aoecmd->cfg ); 128 break; 129 default: 130 return -ENOTSUP; 131 } 132 133 /* Create outgoing I/O buffer */ 134 iobuf = alloc_iob ( ETH_HLEN + sizeof ( *aoehdr ) + 135 aoecmdlen + data_out_len ); 136 137 if ( ! iobuf ) 138 return -ENOMEM; 139 iob_reserve ( iobuf, ETH_HLEN ); 140 aoehdr = iob_put ( iobuf, sizeof ( *aoehdr ) ); 141 aoecmd = iob_put ( iobuf, aoecmdlen ); 142 memset ( aoehdr, 0, ( sizeof ( *aoehdr ) + aoecmdlen ) ); 143 144 /* Fill AoE header */ 145 aoehdr->ver_flags = AOE_VERSION; 146 aoehdr->major = htons ( aoe->major ); 147 aoehdr->minor = aoe->minor; 148 aoehdr->command = aoe->aoe_cmd_type; 149 aoehdr->tag = htonl ( ++aoe->tag ); 150 151 /* Fill AoE payload */ 152 switch ( aoe->aoe_cmd_type ) { 153 case AOE_CMD_ATA: 154 /* Fill AoE command */ 155 aoeata = &aoecmd->ata; 156 linker_assert ( AOE_FL_DEV_HEAD == ATA_DEV_SLAVE, 157 __fix_ata_h__ ); 158 aoeata->aflags = ( ( command->cb.lba48 ? AOE_FL_EXTENDED : 0 )| 159 ( command->cb.device & ATA_DEV_SLAVE ) | 160 ( data_out_len ? AOE_FL_WRITE : 0 ) ); 161 aoeata->err_feat = command->cb.err_feat.bytes.cur; 162 aoeata->count = count; 163 aoeata->cmd_stat = command->cb.cmd_stat; 164 aoeata->lba.u64 = cpu_to_le64 ( command->cb.lba.native ); 165 if ( ! command->cb.lba48 ) 166 aoeata->lba.bytes[3] |= 167 ( command->cb.device & ATA_DEV_MASK ); 168 169 /* Fill data payload */ 170 copy_from_user ( iob_put ( iobuf, data_out_len ), 171 command->data_out, aoe->command_offset, 172 data_out_len ); 173 break; 174 case AOE_CMD_CONFIG: 175 /* Nothing to do */ 176 break; 177 default: 178 assert ( 0 ); 179 } 180 181 /* Send packet */ 182 return net_tx ( iobuf, aoe->netdev, &aoe_protocol, aoe->target ); 183 } 184 185 /** 186 * Handle AoE retry timer expiry 187 * 188 * @v timer AoE retry timer 189 * @v fail Failure indicator 190 */ 191 static void aoe_timer_expired ( struct retry_timer *timer, int fail ) { 192 struct aoe_session *aoe = 193 container_of ( timer, struct aoe_session, timer ); 194 195 if ( fail ) { 196 aoe_done ( aoe, -ETIMEDOUT ); 197 } else { 198 aoe_send_command ( aoe ); 199 } 200 } 201 202 /** 203 * Handle AoE configuration command response 204 * 205 * @v aoe AoE session 206 * @v ll_source Link-layer source address 207 * @ret rc Return status code 208 */ 209 static int aoe_rx_cfg ( struct aoe_session *aoe, const void *ll_source ) { 210 211 /* Record target MAC address */ 212 memcpy ( aoe->target, ll_source, sizeof ( aoe->target ) ); 213 DBGC ( aoe, "AoE %p target MAC address %s\n", 214 aoe, eth_ntoa ( aoe->target ) ); 215 216 /* Mark config request as complete */ 217 aoe_done ( aoe, 0 ); 218 219 return 0; 220 } 221 222 /** 223 * Handle AoE ATA command response 224 * 225 * @v aoe AoE session 226 * @v aoeata AoE ATA command 227 * @v len Length of AoE ATA command 228 * @ret rc Return status code 229 */ 230 static int aoe_rx_ata ( struct aoe_session *aoe, struct aoeata *aoeata, 231 size_t len ) { 232 struct ata_command *command = aoe->command; 233 unsigned int rx_data_len; 234 unsigned int count; 235 unsigned int data_len; 236 237 /* Sanity check */ 238 if ( len < sizeof ( *aoeata ) ) { 239 /* Ignore packet; allow timer to trigger retransmit */ 240 return -EINVAL; 241 } 242 rx_data_len = ( len - sizeof ( *aoeata ) ); 243 244 /* Calculate count and data_len for this subcommand */ 245 count = command->cb.count.native; 246 if ( count > AOE_MAX_COUNT ) 247 count = AOE_MAX_COUNT; 248 data_len = count * ATA_SECTOR_SIZE; 249 250 /* Merge into overall ATA status */ 251 aoe->status |= aoeata->cmd_stat; 252 253 /* Copy data payload */ 254 if ( command->data_in ) { 255 if ( rx_data_len > data_len ) 256 rx_data_len = data_len; 257 copy_to_user ( command->data_in, aoe->command_offset, 258 aoeata->data, rx_data_len ); 259 } 260 261 /* Update ATA command and offset */ 262 aoe->command_offset += data_len; 263 command->cb.lba.native += count; 264 command->cb.count.native -= count; 265 266 /* Check for operation complete */ 267 if ( ! command->cb.count.native ) { 268 aoe_done ( aoe, 0 ); 269 return 0; 270 } 271 272 /* Transmit next portion of request */ 273 stop_timer ( &aoe->timer ); 274 aoe_send_command ( aoe ); 275 276 return 0; 277 } 278 279 /** 280 * Process incoming AoE packets 281 * 282 * @v iobuf I/O buffer 283 * @v netdev Network device 284 * @v ll_source Link-layer source address 285 * @ret rc Return status code 286 * 287 */ 288 static int aoe_rx ( struct io_buffer *iobuf, 289 struct net_device *netdev __unused, 290 const void *ll_source ) { 291 struct aoehdr *aoehdr = iobuf->data; 292 struct aoe_session *aoe; 293 int rc = 0; 294 295 /* Sanity checks */ 296 if ( iob_len ( iobuf ) < sizeof ( *aoehdr ) ) { 297 rc = -EINVAL; 298 goto done; 299 } 300 if ( ( aoehdr->ver_flags & AOE_VERSION_MASK ) != AOE_VERSION ) { 301 rc = -EPROTONOSUPPORT; 302 goto done; 303 } 304 if ( ! ( aoehdr->ver_flags & AOE_FL_RESPONSE ) ) { 305 /* Ignore AoE requests that we happen to see */ 306 goto done; 307 } 308 iob_pull ( iobuf, sizeof ( *aoehdr ) ); 309 310 /* Demultiplex amongst active AoE sessions */ 311 list_for_each_entry ( aoe, &aoe_sessions, list ) { 312 if ( ntohs ( aoehdr->major ) != aoe->major ) 313 continue; 314 if ( aoehdr->minor != aoe->minor ) 315 continue; 316 if ( ntohl ( aoehdr->tag ) != aoe->tag ) 317 continue; 318 if ( aoehdr->ver_flags & AOE_FL_ERROR ) { 319 aoe_done ( aoe, -EIO ); 320 break; 321 } 322 switch ( aoehdr->command ) { 323 case AOE_CMD_ATA: 324 rc = aoe_rx_ata ( aoe, iobuf->data, iob_len ( iobuf )); 325 break; 326 case AOE_CMD_CONFIG: 327 rc = aoe_rx_cfg ( aoe, ll_source ); 328 break; 329 default: 330 DBGC ( aoe, "AoE %p ignoring command %02x\n", 331 aoe, aoehdr->command ); 332 break; 333 } 334 break; 335 } 336 337 done: 338 free_iob ( iobuf ); 339 return rc; 340 } 341 342 /** AoE protocol */ 343 struct net_protocol aoe_protocol __net_protocol = { 344 .name = "AoE", 345 .net_proto = htons ( ETH_P_AOE ), 346 .rx = aoe_rx, 347 }; 348 349 /** 350 * Issue ATA command via an open AoE session 351 * 352 * @v ata ATA device 353 * @v command ATA command 354 * @ret rc Return status code 355 */ 356 static int aoe_command ( struct ata_device *ata, 357 struct ata_command *command ) { 358 struct aoe_session *aoe = 359 container_of ( ata->backend, struct aoe_session, refcnt ); 360 361 aoe->command = command; 362 aoe->status = 0; 363 aoe->command_offset = 0; 364 aoe->aoe_cmd_type = AOE_CMD_ATA; 365 366 aoe_send_command ( aoe ); 367 368 return 0; 369 } 370 371 /** 372 * Issue AoE config query for AoE target discovery 373 * 374 * @v aoe AoE session 375 * @ret rc Return status code 376 */ 377 static int aoe_discover ( struct aoe_session *aoe ) { 378 int rc; 379 380 aoe->status = 0; 381 aoe->aoe_cmd_type = AOE_CMD_CONFIG; 382 aoe->command = NULL; 383 384 aoe_send_command ( aoe ); 385 386 aoe->rc = -EINPROGRESS; 387 while ( aoe->rc == -EINPROGRESS ) 388 step(); 389 rc = aoe->rc; 390 391 return rc; 392 } 393 394 static int aoe_detached_command ( struct ata_device *ata __unused, 395 struct ata_command *command __unused ) { 396 return -ENODEV; 397 } 398 399 void aoe_detach ( struct ata_device *ata ) { 400 struct aoe_session *aoe = 401 container_of ( ata->backend, struct aoe_session, refcnt ); 402 403 stop_timer ( &aoe->timer ); 404 ata->command = aoe_detached_command; 405 list_del ( &aoe->list ); 406 ref_put ( ata->backend ); 407 ata->backend = NULL; 408 } 409 410 static int aoe_parse_root_path ( struct aoe_session *aoe, 411 const char *root_path ) { 412 char *ptr; 413 414 if ( strncmp ( root_path, "aoe:", 4 ) != 0 ) 415 return -EINVAL; 416 ptr = ( ( char * ) root_path + 4 ); 417 418 if ( *ptr++ != 'e' ) 419 return -EINVAL; 420 421 aoe->major = strtoul ( ptr, &ptr, 10 ); 422 if ( *ptr++ != '.' ) 423 return -EINVAL; 424 425 aoe->minor = strtoul ( ptr, &ptr, 10 ); 426 if ( *ptr ) 427 return -EINVAL; 428 429 return 0; 430 } 431 432 int aoe_attach ( struct ata_device *ata, struct net_device *netdev, 433 const char *root_path ) { 434 struct aoe_session *aoe; 435 int rc; 436 437 /* Allocate and initialise structure */ 438 aoe = zalloc ( sizeof ( *aoe ) ); 439 if ( ! aoe ) 440 return -ENOMEM; 441 aoe->refcnt.free = aoe_free; 442 aoe->netdev = netdev_get ( netdev ); 443 memcpy ( aoe->target, netdev->ll_broadcast, sizeof ( aoe->target ) ); 444 aoe->tag = AOE_TAG_MAGIC; 445 aoe->timer.expired = aoe_timer_expired; 446 447 /* Parse root path */ 448 if ( ( rc = aoe_parse_root_path ( aoe, root_path ) ) != 0 ) 449 goto err; 450 451 /* Attach parent interface, transfer reference to connection 452 * list, and return 453 */ 454 ata->backend = ref_get ( &aoe->refcnt ); 455 ata->command = aoe_command; 456 list_add ( &aoe->list, &aoe_sessions ); 457 458 /* Send discovery packet to find the target MAC address. 459 * Ideally, this ought to be done asynchronously, but the 460 * block device interface does not yet support asynchronous 461 * operation. 462 */ 463 if ( ( rc = aoe_discover( aoe ) ) != 0 ) 464 goto err; 465 466 return 0; 467 468 err: 469 ref_put ( &aoe->refcnt ); 470 return rc; 471 } 472