Handle multi-sector reads by splitting them into subcommands.
[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 <vsprintf.h>
22 #include <errno.h>
23 #include <assert.h>
24 #include <byteswap.h>
25 #include <gpxe/list.h>
26 #include <gpxe/if_ether.h>
27 #include <gpxe/pkbuff.h>
28 #include <gpxe/uaccess.h>
29 #include <gpxe/ata.h>
30 #include <gpxe/netdevice.h>
31 #include <gpxe/process.h>
32 #include <gpxe/aoe.h>
33
34 /** @file
35  *
36  * AoE protocol
37  *
38  */
39
40 struct net_protocol aoe_protocol;
41
42 /** List of all AoE sessions */
43 static LIST_HEAD ( aoe_sessions );
44
45 /**
46  * Send AoE command
47  *
48  * @v aoe               AoE session
49  * @ret rc              Return status code
50  *
51  * This transmits an AoE command packet.  It does not wait for a
52  * response.
53  */
54 static int aoe_send_command ( struct aoe_session *aoe ) {
55         struct ata_command *command = aoe->command;
56         struct pk_buff *pkb;
57         struct aoehdr *aoehdr;
58         struct aoecmd *aoecmd;
59
60         /* Create outgoing packet buffer */
61         pkb = alloc_pkb ( ETH_HLEN + sizeof ( *aoehdr ) + sizeof ( *aoecmd ) +
62                           command->data_out_len );
63         if ( ! pkb )
64                 return -ENOMEM;
65         pkb->net_protocol = &aoe_protocol;
66         pkb_reserve ( pkb, ETH_HLEN );
67         aoehdr = pkb_put ( pkb, sizeof ( *aoehdr ) );
68         aoecmd = pkb_put ( pkb, sizeof ( *aoecmd ) );
69         memset ( aoehdr, 0, ( sizeof ( *aoehdr ) + sizeof ( *aoecmd ) ) );
70
71         /* Fill AoE header */
72         aoehdr->ver_flags = AOE_VERSION;
73         aoehdr->major = htons ( aoe->major );
74         aoehdr->minor = aoe->minor;
75         aoehdr->tag = htonl ( ++aoe->tag );
76
77         /* Fill AoE command */
78         linker_assert ( AOE_FL_DEV_HEAD == ATA_DEV_SLAVE, __fix_ata_h__ );
79         aoecmd->aflags = ( ( command->cb.lba48 ? AOE_FL_EXTENDED : 0 ) |
80                            ( command->cb.device & ATA_DEV_SLAVE ) |
81                            ( command->data_out_len ? AOE_FL_WRITE : 0 ) );
82         aoecmd->err_feat = command->cb.err_feat.bytes.cur;
83         aoecmd->count = command->cb.count.bytes.cur;
84         aoecmd->cmd_stat = command->cb.cmd_stat;
85         aoecmd->lba.u64 = cpu_to_le64 ( command->cb.lba.native );
86         if ( ! command->cb.lba48 )
87                 aoecmd->lba.bytes[3] |= ( command->cb.device & ATA_DEV_MASK );
88
89         /* Fill data payload */
90         copy_from_user ( pkb_put ( pkb, command->data_out_len ),
91                          command->data_out, aoe->command_offset,
92                          command->data_out_len );
93
94         /* Send packet */
95         return net_transmit_via ( pkb, aoe->netdev );
96 }
97
98 /**
99  * Handle AoE response
100  *
101  * @v aoe               AoE session
102  * @v aoehdr            AoE header
103  * @ret rc              Return status code
104  */
105 static int aoe_rx_response ( struct aoe_session *aoe, struct aoehdr *aoehdr,
106                              unsigned int len ) {
107         struct aoecmd *aoecmd = aoehdr->arg.command;
108         struct ata_command *command = aoe->command;
109         unsigned int data_in_len;
110         
111         /* Sanity check */
112         if ( len < ( sizeof ( *aoehdr ) + sizeof ( *aoecmd ) ) )
113                 return -EINVAL;
114
115         /* Set overall status code */
116         aoe->status = ( ( aoehdr->ver_flags & AOE_FL_ERROR ) ?
117                         aoehdr->error : 0 );
118
119         /* Copy ATA results */
120         command->cb.err_feat.bytes.cur = aoecmd->err_feat;
121         command->cb.count.bytes.cur = aoecmd->count;
122         command->cb.cmd_stat = aoecmd->cmd_stat;
123         command->cb.lba.native = le64_to_cpu ( aoecmd->lba.u64 );
124         command->cb.lba.bytes.pad = 0;
125         
126         /* Copy data payload */
127         data_in_len = ( len - sizeof ( *aoehdr ) - sizeof ( *aoecmd ) );
128         if ( data_in_len > command->data_in_len ) {
129                 data_in_len = command->data_in_len;
130                 aoe->status |= AOE_STATUS_OVERRUN;
131         } else if ( data_in_len < command->data_in_len ) {
132                 aoe->status |= AOE_STATUS_UNDERRUN;
133         }
134         copy_to_user ( command->data_in, aoe->command_offset,
135                        aoecmd->data, data_in_len );
136
137         return 0;
138 }
139
140 /**
141  * Process incoming AoE packets
142  *
143  * @v pkb               Packet buffer
144  * @ret rc              Return status code
145  *
146  */
147 static int aoe_rx ( struct pk_buff *pkb ) {
148         struct aoehdr *aoehdr = pkb->data;
149         unsigned int len = pkb_len ( pkb );
150         struct aoe_session *aoe;
151         int rc = 0;
152
153         /* Sanity checks */
154         if ( len < sizeof ( *aoehdr ) ) {
155                 rc = -EINVAL;
156                 goto done;
157         }
158         if ( ( aoehdr->ver_flags & AOE_VERSION_MASK ) != AOE_VERSION ) {
159                 rc = -EPROTONOSUPPORT;
160                 goto done;
161         }
162         if ( ! ( aoehdr->ver_flags & AOE_FL_RESPONSE ) ) {
163                 /* Ignore AoE requests that we happen to see */
164                 goto done;
165         }
166
167         /* Demultiplex amongst active AoE sessions */
168         list_for_each_entry ( aoe, &aoe_sessions, list ) {
169                 if ( ntohs ( aoehdr->major ) != aoe->major )
170                         continue;
171                 if ( aoehdr->minor != aoe->minor )
172                         continue;
173                 if ( ntohl ( aoehdr->tag ) != aoe->tag )
174                         continue;
175
176 #warning "Need a way to get the MAC address for future reference"
177
178                 rc = aoe_rx_response ( aoe, aoehdr, len );
179                 break;
180         }
181
182  done:
183         free_pkb ( pkb );
184         return rc;
185 }
186
187 /**
188  * Perform AoE network-layer routing
189  *
190  * @v pkb       Packet buffer
191  * @ret source  Network-layer source address
192  * @ret dest    Network-layer destination address
193  * @ret rc      Return status code
194  */
195 static int aoe_route ( const struct pk_buff *pkb __unused,
196                        struct net_header *nethdr ) {
197
198 #warning "Need a way to find out the MAC address"
199         nethdr->flags = PKT_FL_BROADCAST;
200         return 0;
201 }
202
203 /** AoE protocol */
204 struct net_protocol aoe_protocol = {
205         .name = "AoE",
206         .net_proto = htons ( ETH_P_AOE ),
207         .rx_process = aoe_rx,
208         .route = aoe_route,
209 };
210
211 NET_PROTOCOL ( aoe_protocol );
212
213 /**
214  * Open AoE session
215  *
216  * @v aoe               AoE session
217  */
218 void aoe_open ( struct aoe_session *aoe ) {
219         list_add ( &aoe->list, &aoe_sessions );
220 }
221
222 /**
223  * Close AoE session
224  *
225  * @v aoe               AoE session
226  */
227 void aoe_close ( struct aoe_session *aoe ) {
228         list_del ( &aoe->list );
229 }
230
231 /**
232  * Kick an AoE session into life
233  *
234  * @v aoe               AoE session
235  *
236  * Transmits an AoE request.  Call this function to issue a new
237  * command, or when a retransmission timer expires.
238  */
239 void aoe_kick ( struct aoe_session *aoe ) {
240         aoe_send_command ( aoe );
241 }
242
243 /**
244  * Issue ATA command via an open AoE session
245  *
246  * @v aoe               AoE session
247  * @v command           ATA command
248  * @ret rc              Return status code
249  *
250  * The ATA command must fit within a single AoE frame (i.e. the sector
251  * count must not exceed AOE_MAX_COUNT).
252  */
253 int aoe_issue ( struct aoe_session *aoe, struct ata_command *command ) {
254         aoe->command = command;
255         aoe->status = AOE_STATUS_PENDING;
256
257         aoe_kick ( aoe );
258         while ( aoe->status & AOE_STATUS_PENDING ) {
259                 step();
260         }
261         aoe->command = NULL;
262
263         return ( ( aoe->status & AOE_STATUS_ERR_MASK ) ? -EIO : 0 );
264 }
265
266 /**
267  * Issue ATA command via an open AoE session
268  *
269  * @v aoe               AoE session
270  * @v command           ATA command
271  * @ret rc              Return status code
272  *
273  * The ATA command will be split into several smaller ATA commands,
274  * each with a sector count no larger than AOE_MAX_COUNT.
275  */
276 int aoe_issue_split ( struct aoe_session *aoe, struct ata_command *command ) {
277         struct ata_command subcommand;
278         unsigned int offset;
279         unsigned int count;
280         unsigned int data_len;
281         unsigned int status = 0;
282         int rc = 0;
283
284         /* Split ATA command into AoE-sized subcommands */
285         for ( offset = 0; offset < command->cb.count.native; offset += count ){
286                 memcpy ( &subcommand, command, sizeof ( subcommand ) );
287                 count = ( command->cb.count.native - offset );
288                 if ( count > AOE_MAX_COUNT )
289                         count = AOE_MAX_COUNT;
290                 data_len = count * ATA_SECTOR_SIZE;
291                 if ( subcommand.data_in_len )
292                         subcommand.data_in_len = data_len;
293                 if ( subcommand.data_out_len )
294                         subcommand.data_out_len = data_len;
295                 aoe->command_offset = ( offset * ATA_SECTOR_SIZE );
296                 subcommand.cb.lba.native += offset;
297                 subcommand.cb.count.native = count;
298                 if ( ( rc = aoe_issue ( aoe, &subcommand ) ) != 0 )
299                         goto done;
300                 status |= subcommand.cb.cmd_stat;
301         }
302         command->cb.cmd_stat = status;
303
304  done:
305         aoe->command_offset = 0;
306         return rc;
307 }