2 * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
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.
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.
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.
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>
32 #include <gpxe/netdevice.h>
33 #include <gpxe/process.h>
34 #include <gpxe/features.h>
43 FEATURE ( FEATURE_PROTOCOL
, "AoE", DHCP_EB_FEATURE_AOE
, 1 );
45 struct net_protocol aoe_protocol
;
47 /** List of all AoE sessions */
48 static LIST_HEAD ( aoe_sessions
);
50 static void aoe_free ( struct refcnt
*refcnt
) {
51 struct aoe_session
*aoe
=
52 container_of ( refcnt
, struct aoe_session
, refcnt
);
54 netdev_put ( aoe
->netdev
);
59 * Mark current AoE command complete
62 * @v rc Return status code
64 static void aoe_done ( struct aoe_session
*aoe
, int rc
) {
66 /* Record overall command status */
67 aoe
->command
->cb
.cmd_stat
= aoe
->status
;
70 /* Mark operation as complete */
78 * @ret rc Return status code
80 * This transmits an AoE command packet. It does not wait for a
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
;
89 unsigned int data_out_len
;
91 /* Fail immediately if we have no netdev to send on */
92 if ( ! aoe
->netdev
) {
93 aoe_done ( aoe
, -ENETUNREACH
);
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 );
103 /* Create outgoing I/O buffer */
104 iobuf
= alloc_iob ( ETH_HLEN
+ sizeof ( *aoehdr
) + sizeof ( *aoecmd
) +
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
) ) );
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
);
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
);
131 /* Fill data payload */
132 copy_from_user ( iob_put ( iobuf
, data_out_len
), command
->data_out
,
133 aoe
->command_offset
, data_out_len
);
136 start_timer ( &aoe
->timer
);
137 return net_tx ( iobuf
, aoe
->netdev
, &aoe_protocol
, aoe
->target
);
141 * Handle AoE retry timer expiry
143 * @v timer AoE retry timer
144 * @v fail Failure indicator
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
);
151 aoe_done ( aoe
, -ETIMEDOUT
);
153 aoe_send_command ( aoe
);
158 * Handle AoE response
161 * @v aoehdr AoE header
162 * @ret rc Return status code
164 static int aoe_rx_response ( struct aoe_session
*aoe
, struct aoehdr
*aoehdr
,
166 struct aoecmd
*aoecmd
= aoehdr
->arg
.command
;
167 struct ata_command
*command
= aoe
->command
;
168 unsigned int rx_data_len
;
170 unsigned int data_len
;
173 if ( len
< ( sizeof ( *aoehdr
) + sizeof ( *aoecmd
) ) ) {
174 /* Ignore packet; allow timer to trigger retransmit */
177 rx_data_len
= ( len
- sizeof ( *aoehdr
) - sizeof ( *aoecmd
) );
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.
183 stop_timer ( &aoe
->timer
);
185 /* Check for fatal errors */
186 if ( aoehdr
->ver_flags
& AOE_FL_ERROR
) {
187 aoe_done ( aoe
, -EIO
);
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
;
197 /* Merge into overall ATA status */
198 aoe
->status
|= aoecmd
->cmd_stat
;
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
);
208 /* Update ATA command and offset */
209 aoe
->command_offset
+= data_len
;
210 command
->cb
.lba
.native
+= count
;
211 command
->cb
.count
.native
-= count
;
213 /* Check for operation complete */
214 if ( ! command
->cb
.count
.native
) {
219 /* Transmit next portion of request */
220 aoe_send_command ( aoe
);
226 * Process incoming AoE packets
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
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
;
242 if ( len
< sizeof ( *aoehdr
) ) {
246 if ( ( aoehdr
->ver_flags
& AOE_VERSION_MASK
) != AOE_VERSION
) {
247 rc
= -EPROTONOSUPPORT
;
250 if ( ! ( aoehdr
->ver_flags
& AOE_FL_RESPONSE
) ) {
251 /* Ignore AoE requests that we happen to see */
255 /* Demultiplex amongst active AoE sessions */
256 list_for_each_entry ( aoe
, &aoe_sessions
, list
) {
257 if ( ntohs ( aoehdr
->major
) != aoe
->major
)
259 if ( aoehdr
->minor
!= aoe
->minor
)
261 if ( ntohl ( aoehdr
->tag
) != aoe
->tag
)
263 memcpy ( aoe
->target
, ll_source
, sizeof ( aoe
->target
) );
264 rc
= aoe_rx_response ( aoe
, aoehdr
, len
);
274 struct net_protocol aoe_protocol __net_protocol
= {
276 .net_proto
= htons ( ETH_P_AOE
),
281 * Issue ATA command via an open AoE session
284 * @v command ATA command
285 * @ret rc Return status code
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
);
293 aoe
->command
= command
;
295 aoe
->command_offset
= 0;
296 aoe_send_command ( aoe
);
298 aoe
->rc
= -EINPROGRESS
;
299 while ( aoe
->rc
== -EINPROGRESS
)
306 static int aoe_detached_command ( struct ata_device
*ata __unused
,
307 struct ata_command
*command __unused
) {
311 void aoe_detach ( struct ata_device
*ata
) {
312 struct aoe_session
*aoe
=
313 container_of ( ata
->backend
, struct aoe_session
, refcnt
);
315 stop_timer ( &aoe
->timer
);
316 ata
->command
= aoe_detached_command
;
317 list_del ( &aoe
->list
);
318 ref_put ( ata
->backend
);
322 static int aoe_parse_root_path ( struct aoe_session
*aoe
,
323 const char *root_path
) {
326 if ( strncmp ( root_path
, "aoe:", 4 ) != 0 )
328 ptr
= ( ( char * ) root_path
+ 4 );
333 aoe
->major
= strtoul ( ptr
, &ptr
, 10 );
337 aoe
->minor
= strtoul ( ptr
, &ptr
, 10 );
344 int aoe_attach ( struct ata_device
*ata
, struct net_device
*netdev
,
345 const char *root_path
) {
346 struct aoe_session
*aoe
;
349 /* Allocate and initialise structure */
350 aoe
= zalloc ( sizeof ( *aoe
) );
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
;
360 /* Parse root path */
361 if ( ( rc
= aoe_parse_root_path ( aoe
, root_path
) ) != 0 )
364 /* Attach parent interface, transfer reference to connection
367 ata
->backend
= ref_get ( &aoe
->refcnt
);
368 ata
->command
= aoe_command
;
369 list_add ( &aoe
->list
, &aoe_sessions
);
373 ref_put ( &aoe
->refcnt
);