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