5536ae8da042265b4e4cc892aa128ad237ddfa86
[people/adir/gpxe.git] / src / net / aoe.c
1 /*
2  * Copyright (C) 2006 Michael Brown <mbrown@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 #include <stddef.h>
20 #include <string.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <errno.h>
24 #include <assert.h>
25 #include <byteswap.h>
26 #include <gpxe/list.h>
27 #include <gpxe/if_ether.h>
28 #include <gpxe/ethernet.h>
29 #include <gpxe/iobuf.h>
30 #include <gpxe/uaccess.h>
31 #include <gpxe/ata.h>
32 #include <gpxe/netdevice.h>
33 #include <gpxe/process.h>
34 #include <gpxe/features.h>
35 #include <gpxe/aoe.h>
36
37 /** @file
38  *
39  * AoE protocol
40  *
41  */
42
43 FEATURE ( "AoE", DHCP_EB_FEATURE_AOE );
44
45 struct net_protocol aoe_protocol;
46
47 /** List of all AoE sessions */
48 static LIST_HEAD ( aoe_sessions );
49
50 static void aoe_free ( struct refcnt *refcnt ) {
51         struct aoe_session *aoe =
52                 container_of ( refcnt, struct aoe_session, refcnt );
53
54         netdev_put ( aoe->netdev );
55         free ( aoe );
56 }
57
58 /**
59  * Mark current AoE command complete
60  *
61  * @v aoe               AoE session
62  * @v rc                Return status code
63  */
64 static void aoe_done ( struct aoe_session *aoe, int rc ) {
65
66         /* Record overall command status */
67         aoe->command->cb.cmd_stat = aoe->status;
68         aoe->command = NULL;
69
70         /* Mark operation as complete */
71         aoe->rc = rc;
72 }
73
74 /**
75  * Send AoE command
76  *
77  * @v aoe               AoE session
78  * @ret rc              Return status code
79  *
80  * This transmits an AoE command packet.  It does not wait for a
81  * response.
82  */
83 static int aoe_send_command ( struct aoe_session *aoe ) {
84         struct ata_command *command = aoe->command;
85         struct io_buffer *iobuf;
86         struct aoehdr *aoehdr;
87         struct aoecmd *aoecmd;
88         unsigned int count;
89         unsigned int data_out_len;
90
91         /* Fail immediately if we have no netdev to send on */
92         if ( ! aoe->netdev ) {
93                 aoe_done ( aoe, -ENETUNREACH );
94                 return -ENETUNREACH;
95         }
96
97         /* Calculate count and data_out_len for this subcommand */
98         count = command->cb.count.native;
99         if ( count > AOE_MAX_COUNT )
100                 count = AOE_MAX_COUNT;
101         data_out_len = ( command->data_out ? ( count * ATA_SECTOR_SIZE ) : 0 );
102
103         /* Create outgoing I/O buffer */
104         iobuf = alloc_iob ( ETH_HLEN + sizeof ( *aoehdr ) + sizeof ( *aoecmd ) +
105                           data_out_len );
106         if ( ! iobuf )
107                 return -ENOMEM;
108         iob_reserve ( iobuf, ETH_HLEN );
109         aoehdr = iob_put ( iobuf, sizeof ( *aoehdr ) );
110         aoecmd = iob_put ( iobuf, sizeof ( *aoecmd ) );
111         memset ( aoehdr, 0, ( sizeof ( *aoehdr ) + sizeof ( *aoecmd ) ) );
112
113         /* Fill AoE header */
114         aoehdr->ver_flags = AOE_VERSION;
115         aoehdr->major = htons ( aoe->major );
116         aoehdr->minor = aoe->minor;
117         aoehdr->tag = htonl ( ++aoe->tag );
118
119         /* Fill AoE command */
120         linker_assert ( AOE_FL_DEV_HEAD == ATA_DEV_SLAVE, __fix_ata_h__ );
121         aoecmd->aflags = ( ( command->cb.lba48 ? AOE_FL_EXTENDED : 0 ) |
122                            ( command->cb.device & ATA_DEV_SLAVE ) |
123                            ( data_out_len ? AOE_FL_WRITE : 0 ) );
124         aoecmd->err_feat = command->cb.err_feat.bytes.cur;
125         aoecmd->count = count;
126         aoecmd->cmd_stat = command->cb.cmd_stat;
127         aoecmd->lba.u64 = cpu_to_le64 ( command->cb.lba.native );
128         if ( ! command->cb.lba48 )
129                 aoecmd->lba.bytes[3] |= ( command->cb.device & ATA_DEV_MASK );
130
131         /* Fill data payload */
132         copy_from_user ( iob_put ( iobuf, data_out_len ), command->data_out,
133                          aoe->command_offset, data_out_len );
134
135         /* Send packet */
136         start_timer ( &aoe->timer );
137         return net_tx ( iobuf, aoe->netdev, &aoe_protocol, aoe->target );
138 }
139
140 /**
141  * Handle AoE retry timer expiry
142  *
143  * @v timer             AoE retry timer
144  * @v fail              Failure indicator
145  */
146 static void aoe_timer_expired ( struct retry_timer *timer, int fail ) {
147         struct aoe_session *aoe =
148                 container_of ( timer, struct aoe_session, timer );
149
150         if ( fail ) {
151                 aoe_done ( aoe, -ETIMEDOUT );
152         } else {
153                 aoe_send_command ( aoe );
154         }
155 }
156
157 /**
158  * Handle AoE response
159  *
160  * @v aoe               AoE session
161  * @v aoehdr            AoE header
162  * @ret rc              Return status code
163  */
164 static int aoe_rx_response ( struct aoe_session *aoe, struct aoehdr *aoehdr,
165                              unsigned int len ) {
166         struct aoecmd *aoecmd = aoehdr->arg.command;
167         struct ata_command *command = aoe->command;
168         unsigned int rx_data_len;
169         unsigned int count;
170         unsigned int data_len;
171         
172         /* Sanity check */
173         if ( len < ( sizeof ( *aoehdr ) + sizeof ( *aoecmd ) ) ) {
174                 /* Ignore packet; allow timer to trigger retransmit */
175                 return -EINVAL;
176         }
177         rx_data_len = ( len - sizeof ( *aoehdr ) - sizeof ( *aoecmd ) );
178
179         /* Stop retry timer.  After this point, every code path must
180          * either terminate the AoE operation via aoe_done(), or
181          * transmit a new packet.
182          */
183         stop_timer ( &aoe->timer );
184
185         /* Check for fatal errors */
186         if ( aoehdr->ver_flags & AOE_FL_ERROR ) {
187                 aoe_done ( aoe, -EIO );
188                 return 0;
189         }
190
191         /* Calculate count and data_len for this subcommand */
192         count = command->cb.count.native;
193         if ( count > AOE_MAX_COUNT )
194                 count = AOE_MAX_COUNT;
195         data_len = count * ATA_SECTOR_SIZE;
196
197         /* Merge into overall ATA status */
198         aoe->status |= aoecmd->cmd_stat;
199
200         /* Copy data payload */
201         if ( command->data_in ) {
202                 if ( rx_data_len > data_len )
203                         rx_data_len = data_len;
204                 copy_to_user ( command->data_in, aoe->command_offset,
205                                aoecmd->data, rx_data_len );
206         }
207
208         /* Update ATA command and offset */
209         aoe->command_offset += data_len;
210         command->cb.lba.native += count;
211         command->cb.count.native -= count;
212
213         /* Check for operation complete */
214         if ( ! command->cb.count.native ) {
215                 aoe_done ( aoe, 0 );
216                 return 0;
217         }
218
219         /* Transmit next portion of request */
220         aoe_send_command ( aoe );
221
222         return 0;
223 }
224
225 /**
226  * Process incoming AoE packets
227  *
228  * @v iobuf             I/O buffer
229  * @v netdev            Network device
230  * @v ll_source         Link-layer source address
231  * @ret rc              Return status code
232  *
233  */
234 static int aoe_rx ( struct io_buffer *iobuf, struct net_device *netdev __unused,
235                     const void *ll_source ) {
236         struct aoehdr *aoehdr = iobuf->data;
237         unsigned int len = iob_len ( iobuf );
238         struct aoe_session *aoe;
239         int rc = 0;
240
241         /* Sanity checks */
242         if ( len < sizeof ( *aoehdr ) ) {
243                 rc = -EINVAL;
244                 goto done;
245         }
246         if ( ( aoehdr->ver_flags & AOE_VERSION_MASK ) != AOE_VERSION ) {
247                 rc = -EPROTONOSUPPORT;
248                 goto done;
249         }
250         if ( ! ( aoehdr->ver_flags & AOE_FL_RESPONSE ) ) {
251                 /* Ignore AoE requests that we happen to see */
252                 goto done;
253         }
254
255         /* Demultiplex amongst active AoE sessions */
256         list_for_each_entry ( aoe, &aoe_sessions, list ) {
257                 if ( ntohs ( aoehdr->major ) != aoe->major )
258                         continue;
259                 if ( aoehdr->minor != aoe->minor )
260                         continue;
261                 if ( ntohl ( aoehdr->tag ) != aoe->tag )
262                         continue;
263                 memcpy ( aoe->target, ll_source, sizeof ( aoe->target ) );
264                 rc = aoe_rx_response ( aoe, aoehdr, len );
265                 break;
266         }
267
268  done:
269         free_iob ( iobuf );
270         return rc;
271 }
272
273 /** AoE protocol */
274 struct net_protocol aoe_protocol __net_protocol = {
275         .name = "AoE",
276         .net_proto = htons ( ETH_P_AOE ),
277         .rx = aoe_rx,
278 };
279
280 /**
281  * Issue ATA command via an open AoE session
282  *
283  * @v ata               ATA device
284  * @v command           ATA command
285  * @ret rc              Return status code
286  */
287 static int aoe_command ( struct ata_device *ata,
288                          struct ata_command *command ) {
289         struct aoe_session *aoe =
290                 container_of ( ata->backend, struct aoe_session, refcnt );
291         int rc;
292
293         aoe->command = command;
294         aoe->status = 0;
295         aoe->command_offset = 0;
296         aoe_send_command ( aoe );
297
298         aoe->rc = -EINPROGRESS;
299         while ( aoe->rc == -EINPROGRESS )
300                 step();
301         rc = aoe->rc;
302
303         return rc;
304 }
305
306 static int aoe_detached_command ( struct ata_device *ata __unused,
307                                   struct ata_command *command __unused ) {
308         return -ENODEV;
309 }
310
311 void aoe_detach ( struct ata_device *ata ) {
312         struct aoe_session *aoe =
313                 container_of ( ata->backend, struct aoe_session, refcnt );
314
315         stop_timer ( &aoe->timer );
316         ata->command = aoe_detached_command;
317         list_del ( &aoe->list );
318         ref_put ( ata->backend );
319         ata->backend = NULL;
320 }
321
322 static int aoe_parse_root_path ( struct aoe_session *aoe,
323                                  const char *root_path ) {
324         char *ptr;
325
326         if ( strncmp ( root_path, "aoe:", 4 ) != 0 )
327                 return -EINVAL;
328         ptr = ( ( char * ) root_path + 4 );
329
330         if ( *ptr++ != 'e' )
331                 return -EINVAL;
332
333         aoe->major = strtoul ( ptr, &ptr, 10 );
334         if ( *ptr++ != '.' )
335                 return -EINVAL;
336
337         aoe->minor = strtoul ( ptr, &ptr, 10 );
338         if ( *ptr )
339                 return -EINVAL;
340
341         return 0;
342 }
343
344 int aoe_attach ( struct ata_device *ata, struct net_device *netdev,
345                  const char *root_path ) {
346         struct aoe_session *aoe;
347         int rc;
348
349         /* Allocate and initialise structure */
350         aoe = zalloc ( sizeof ( *aoe ) );
351         if ( ! aoe )
352                 return -ENOMEM;
353         aoe->refcnt.free = aoe_free;
354         aoe->netdev = netdev_get ( netdev );
355         memcpy ( aoe->target, ethernet_protocol.ll_broadcast,
356                  sizeof ( aoe->target ) );
357         aoe->tag = AOE_TAG_MAGIC;
358         aoe->timer.expired = aoe_timer_expired;
359
360         /* Parse root path */
361         if ( ( rc = aoe_parse_root_path ( aoe, root_path ) ) != 0 )
362                 goto err;
363
364         /* Attach parent interface, transfer reference to connection
365          * list, and return
366          */
367         ata->backend = ref_get ( &aoe->refcnt );
368         ata->command = aoe_command;
369         list_add ( &aoe->list, &aoe_sessions );
370         return 0;
371
372  err:
373         ref_put ( &aoe->refcnt );
374         return rc;
375 }