浏览代码

[block] Centralise SAN device abstraction

Create a central SAN device abstraction to be shared between BIOS and
UEFI.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 7 年前
父节点
当前提交
4adc7b0290
共有 3 个文件被更改,包括 687 次插入1 次删除
  1. 563
    0
      src/core/sanboot.c
  2. 1
    0
      src/include/ipxe/errfile.h
  3. 123
    1
      src/include/ipxe/sanboot.h

+ 563
- 0
src/core/sanboot.c 查看文件

@@ -0,0 +1,563 @@
1
+/*
2
+ * Copyright (C) 2017 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., 51 Franklin Street, Fifth Floor, Boston, MA
17
+ * 02110-1301, USA.
18
+ *
19
+ * You can also choose to distribute this program under the terms of
20
+ * the Unmodified Binary Distribution Licence (as given in the file
21
+ * COPYING.UBDL), provided that you have satisfied its requirements.
22
+ */
23
+
24
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
+
26
+/**
27
+ * @file
28
+ *
29
+ * SAN booting
30
+ *
31
+ */
32
+
33
+#include <stdint.h>
34
+#include <stdlib.h>
35
+#include <errno.h>
36
+#include <assert.h>
37
+#include <ipxe/xfer.h>
38
+#include <ipxe/open.h>
39
+#include <ipxe/timer.h>
40
+#include <ipxe/process.h>
41
+#include <ipxe/iso9660.h>
42
+#include <ipxe/sanboot.h>
43
+
44
+/**
45
+ * Timeout for block device commands (in ticks)
46
+ *
47
+ * Underlying devices should ideally never become totally stuck.
48
+ * However, if they do, then the blocking SAN APIs provide no means
49
+ * for the caller to cancel the operation, and the machine appears to
50
+ * hang.  Use an overall timeout for all commands to avoid this
51
+ * problem and bounce timeout failures to the caller.
52
+ */
53
+#define SAN_COMMAND_TIMEOUT ( 15 * TICKS_PER_SEC )
54
+
55
+/** List of SAN devices */
56
+LIST_HEAD ( san_devices );
57
+
58
+/**
59
+ * Find SAN device by drive number
60
+ *
61
+ * @v drive		Drive number
62
+ * @ret sandev		SAN device, or NULL
63
+ */
64
+struct san_device * sandev_find ( unsigned int drive ) {
65
+	struct san_device *sandev;
66
+
67
+	list_for_each_entry ( sandev, &san_devices, list ) {
68
+		if ( sandev->drive == drive )
69
+			return sandev;
70
+	}
71
+	return NULL;
72
+}
73
+
74
+/**
75
+ * Free SAN device
76
+ *
77
+ * @v refcnt		Reference count
78
+ */
79
+static void sandev_free ( struct refcnt *refcnt ) {
80
+	struct san_device *sandev =
81
+		container_of ( refcnt, struct san_device, refcnt );
82
+
83
+	assert ( ! timer_running ( &sandev->timer ) );
84
+	uri_put ( sandev->uri );
85
+	free ( sandev );
86
+}
87
+
88
+/**
89
+ * Close SAN device command
90
+ *
91
+ * @v sandev		SAN device
92
+ * @v rc		Reason for close
93
+ */
94
+static void sandev_command_close ( struct san_device *sandev, int rc ) {
95
+
96
+	/* Stop timer */
97
+	stop_timer ( &sandev->timer );
98
+
99
+	/* Restart interface */
100
+	intf_restart ( &sandev->command, rc );
101
+
102
+	/* Record command status */
103
+	sandev->command_rc = rc;
104
+}
105
+
106
+/**
107
+ * Record SAN device capacity
108
+ *
109
+ * @v sandev		SAN device
110
+ * @v capacity		SAN device capacity
111
+ */
112
+static void sandev_command_capacity ( struct san_device *sandev,
113
+				      struct block_device_capacity *capacity ) {
114
+
115
+	/* Record raw capacity information */
116
+	memcpy ( &sandev->capacity, capacity, sizeof ( sandev->capacity ) );
117
+}
118
+
119
+/** SAN device command interface operations */
120
+static struct interface_operation sandev_command_op[] = {
121
+	INTF_OP ( intf_close, struct san_device *, sandev_command_close ),
122
+	INTF_OP ( block_capacity, struct san_device *,
123
+		  sandev_command_capacity ),
124
+};
125
+
126
+/** SAN device command interface descriptor */
127
+static struct interface_descriptor sandev_command_desc =
128
+	INTF_DESC ( struct san_device, command, sandev_command_op );
129
+
130
+/**
131
+ * Handle SAN device command timeout
132
+ *
133
+ * @v retry		Retry timer
134
+ */
135
+static void sandev_command_expired ( struct retry_timer *timer,
136
+				     int over __unused ) {
137
+	struct san_device *sandev =
138
+		container_of ( timer, struct san_device, timer );
139
+
140
+	sandev_command_close ( sandev, -ETIMEDOUT );
141
+}
142
+
143
+/**
144
+ * Restart SAN device interface
145
+ *
146
+ * @v sandev		SAN device
147
+ * @v rc		Reason for restart
148
+ */
149
+static void sandev_restart ( struct san_device *sandev, int rc ) {
150
+
151
+	/* Restart block device interface */
152
+	intf_nullify ( &sandev->command ); /* avoid potential loops */
153
+	intf_restart ( &sandev->block, rc );
154
+
155
+	/* Close any outstanding command */
156
+	sandev_command_close ( sandev, rc );
157
+
158
+	/* Record device error */
159
+	sandev->block_rc = rc;
160
+}
161
+
162
+/**
163
+ * (Re)open SAN device
164
+ *
165
+ * @v sandev		SAN device
166
+ * @ret rc		Return status code
167
+ *
168
+ * This function will block until the device is available.
169
+ */
170
+int sandev_reopen ( struct san_device *sandev ) {
171
+	int rc;
172
+
173
+	/* Close any outstanding command and restart interface */
174
+	sandev_restart ( sandev, -ECONNRESET );
175
+
176
+	/* Mark device as being not yet open */
177
+	sandev->block_rc = -EINPROGRESS;
178
+
179
+	/* Open block device interface */
180
+	if ( ( rc = xfer_open_uri ( &sandev->block, sandev->uri ) ) != 0 ) {
181
+		DBGC ( sandev, "SAN %#02x could not (re)open URI: %s\n",
182
+		       sandev->drive, strerror ( rc ) );
183
+		return rc;
184
+	}
185
+
186
+	/* Wait for device to become available */
187
+	while ( sandev->block_rc == -EINPROGRESS ) {
188
+		step();
189
+		if ( xfer_window ( &sandev->block ) != 0 ) {
190
+			sandev->block_rc = 0;
191
+			return 0;
192
+		}
193
+	}
194
+
195
+	DBGC ( sandev, "SAN %#02x never became available: %s\n",
196
+	       sandev->drive, strerror ( sandev->block_rc ) );
197
+	return sandev->block_rc;
198
+}
199
+
200
+/**
201
+ * Handle closure of underlying block device interface
202
+ *
203
+ * @v sandev		SAN device
204
+ * @ret rc		Reason for close
205
+ */
206
+static void sandev_block_close ( struct san_device *sandev, int rc ) {
207
+
208
+	/* Any closure is an error from our point of view */
209
+	if ( rc == 0 )
210
+		rc = -ENOTCONN;
211
+	DBGC ( sandev, "SAN %#02x went away: %s\n",
212
+	       sandev->drive, strerror ( rc ) );
213
+
214
+	/* Close any outstanding command and restart interface */
215
+	sandev_restart ( sandev, rc );
216
+}
217
+
218
+/**
219
+ * Check SAN device flow control window
220
+ *
221
+ * @v sandev		SAN device
222
+ */
223
+static size_t sandev_block_window ( struct san_device *sandev __unused ) {
224
+
225
+	/* We are never ready to receive data via this interface.
226
+	 * This prevents objects that support both block and stream
227
+	 * interfaces from attempting to send us stream data.
228
+	 */
229
+	return 0;
230
+}
231
+
232
+/** SAN device block interface operations */
233
+static struct interface_operation sandev_block_op[] = {
234
+	INTF_OP ( intf_close, struct san_device *, sandev_block_close ),
235
+	INTF_OP ( xfer_window, struct san_device *, sandev_block_window ),
236
+};
237
+
238
+/** SAN device block interface descriptor */
239
+static struct interface_descriptor sandev_block_desc =
240
+	INTF_DESC ( struct san_device, block, sandev_block_op );
241
+
242
+/** SAN device read/write command parameters */
243
+struct san_command_rw_params {
244
+	/** SAN device read/write operation */
245
+	int ( * block_rw ) ( struct interface *control, struct interface *data,
246
+			     uint64_t lba, unsigned int count,
247
+			     userptr_t buffer, size_t len );
248
+	/** Data buffer */
249
+	userptr_t buffer;
250
+	/** Starting LBA */
251
+	uint64_t lba;
252
+	/** Block count */
253
+	unsigned int count;
254
+};
255
+
256
+/** SAN device command parameters */
257
+union san_command_params {
258
+	/** Read/write command parameters */
259
+	struct san_command_rw_params rw;
260
+};
261
+
262
+/**
263
+ * Initiate SAN device read/write command
264
+ *
265
+ * @v sandev		SAN device
266
+ * @v params		Command parameters
267
+ * @ret rc		Return status code
268
+ */
269
+static int sandev_command_rw ( struct san_device *sandev,
270
+			       const union san_command_params *params ) {
271
+	size_t len = ( params->rw.count * sandev->capacity.blksize );
272
+	int rc;
273
+
274
+	/* Initiate read/write command */
275
+	if ( ( rc = params->rw.block_rw ( &sandev->block, &sandev->command,
276
+					  params->rw.lba, params->rw.count,
277
+					  params->rw.buffer, len ) ) != 0 ) {
278
+		DBGC ( sandev, "SAN %#02x could not initiate read/write: "
279
+		       "%s\n", sandev->drive, strerror ( rc ) );
280
+		return rc;
281
+	}
282
+
283
+	return 0;
284
+}
285
+
286
+/**
287
+ * Initiate SAN device read capacity command
288
+ *
289
+ * @v sandev		SAN device
290
+ * @v params		Command parameters
291
+ * @ret rc		Return status code
292
+ */
293
+static int
294
+sandev_command_read_capacity ( struct san_device *sandev,
295
+			       const union san_command_params *params __unused){
296
+	int rc;
297
+
298
+	/* Initiate read capacity command */
299
+	if ( ( rc = block_read_capacity ( &sandev->block,
300
+					  &sandev->command ) ) != 0 ) {
301
+		DBGC ( sandev, "SAN %#02x could not initiate read capacity: "
302
+		       "%s\n", sandev->drive, strerror ( rc ) );
303
+		return rc;
304
+	}
305
+
306
+	return 0;
307
+}
308
+
309
+/**
310
+ * Execute a single SAN device command and wait for completion
311
+ *
312
+ * @v sandev		SAN device
313
+ * @v command		Command
314
+ * @v params		Command parameters (if required)
315
+ * @ret rc		Return status code
316
+ */
317
+static int
318
+sandev_command ( struct san_device *sandev,
319
+		 int ( * command ) ( struct san_device *sandev,
320
+				     const union san_command_params *params ),
321
+		 const union san_command_params *params ) {
322
+	int rc;
323
+
324
+	/* Sanity check */
325
+	assert ( ! timer_running ( &sandev->timer ) );
326
+
327
+	/* Reopen block device if applicable */
328
+	if ( sandev_needs_reopen ( sandev ) &&
329
+	     ( ( rc = sandev_reopen ( sandev ) ) != 0 ) ) {
330
+	     goto err_reopen;
331
+	}
332
+
333
+	/* Start expiry timer */
334
+	start_timer_fixed ( &sandev->timer, SAN_COMMAND_TIMEOUT );
335
+
336
+	/* Initiate command */
337
+	if ( ( rc = command ( sandev, params ) ) != 0 )
338
+		goto err_op;
339
+
340
+	/* Wait for command to complete */
341
+	while ( timer_running ( &sandev->timer ) )
342
+		step();
343
+
344
+	/* Collect return status */
345
+	rc = sandev->command_rc;
346
+
347
+	return rc;
348
+
349
+ err_op:
350
+	stop_timer ( &sandev->timer );
351
+ err_reopen:
352
+	return rc;
353
+}
354
+
355
+/**
356
+ * Reset SAN device
357
+ *
358
+ * @v sandev		SAN device
359
+ * @ret rc		Return status code
360
+ */
361
+int sandev_reset ( struct san_device *sandev ) {
362
+	int rc;
363
+
364
+	DBGC ( sandev, "SAN %#02x reset\n", sandev->drive );
365
+
366
+	/* Close and reopen underlying block device */
367
+	if ( ( rc = sandev_reopen ( sandev ) ) != 0 )
368
+		return rc;
369
+
370
+	return 0;
371
+}
372
+
373
+/**
374
+ * Read from or write to SAN device
375
+ *
376
+ * @v sandev		SAN device
377
+ * @v lba		Starting logical block address
378
+ * @v count		Number of logical blocks
379
+ * @v buffer		Data buffer
380
+ * @v block_rw		Block read/write method
381
+ * @ret rc		Return status code
382
+ */
383
+int sandev_rw ( struct san_device *sandev, uint64_t lba,
384
+		unsigned int count, userptr_t buffer,
385
+		int ( * block_rw ) ( struct interface *control,
386
+				     struct interface *data,
387
+				     uint64_t lba, unsigned int count,
388
+				     userptr_t buffer, size_t len ) ) {
389
+	union san_command_params params;
390
+	unsigned int remaining;
391
+	size_t frag_len;
392
+	int rc;
393
+
394
+	/* Initialise command parameters */
395
+	params.rw.block_rw = block_rw;
396
+	params.rw.buffer = buffer;
397
+	params.rw.lba = ( lba << sandev->blksize_shift );
398
+	params.rw.count = sandev->capacity.max_count;
399
+	remaining = ( count << sandev->blksize_shift );
400
+
401
+	/* Read/write fragments */
402
+	while ( remaining ) {
403
+
404
+		/* Determine fragment length */
405
+		if ( params.rw.count > remaining )
406
+			params.rw.count = remaining;
407
+
408
+		/* Execute command */
409
+		if ( ( rc = sandev_command ( sandev, sandev_command_rw,
410
+					     &params ) ) != 0 )
411
+			return rc;
412
+
413
+		/* Move to next fragment */
414
+		frag_len = ( sandev->capacity.blksize * params.rw.count );
415
+		params.rw.buffer = userptr_add ( params.rw.buffer, frag_len );
416
+		params.rw.lba += params.rw.count;
417
+		remaining -= params.rw.count;
418
+	}
419
+
420
+	return 0;
421
+}
422
+
423
+/**
424
+ * Configure SAN device as a CD-ROM, if applicable
425
+ *
426
+ * @v sandev		SAN device
427
+ * @ret rc		Return status code
428
+ *
429
+ * Both BIOS and UEFI require SAN devices to be accessed with a block
430
+ * size of 2048.  While we could require the user to configure the
431
+ * block size appropriately, this is non-trivial and would impose a
432
+ * substantial learning effort on the user.  Instead, we check for the
433
+ * presence of the ISO9660 primary volume descriptor and, if found,
434
+ * then we force a block size of 2048 and map read/write requests
435
+ * appropriately.
436
+ */
437
+static int sandev_parse_iso9660 ( struct san_device *sandev ) {
438
+	static const struct iso9660_primary_descriptor_fixed primary_check = {
439
+		.type = ISO9660_TYPE_PRIMARY,
440
+		.id = ISO9660_ID,
441
+	};
442
+	struct iso9660_primary_descriptor *primary;
443
+	unsigned int blksize;
444
+	unsigned int blksize_shift;
445
+	unsigned int lba;
446
+	unsigned int count;
447
+	int rc;
448
+
449
+	/* Calculate required blocksize shift for potential CD-ROM access */
450
+	blksize = sandev->capacity.blksize;
451
+	blksize_shift = 0;
452
+	while ( blksize < ISO9660_BLKSIZE ) {
453
+		blksize <<= 1;
454
+		blksize_shift++;
455
+	}
456
+	if ( blksize > ISO9660_BLKSIZE ) {
457
+		/* Cannot be a CD-ROM.  This is not an error. */
458
+		rc = 0;
459
+		goto invalid_blksize;
460
+	}
461
+	lba = ( ISO9660_PRIMARY_LBA << blksize_shift );
462
+	count = ( 1 << blksize_shift );
463
+
464
+	/* Allocate scratch area */
465
+	primary = malloc ( ISO9660_BLKSIZE );
466
+	if ( ! primary ) {
467
+		rc = -ENOMEM;
468
+		goto err_alloc;
469
+	}
470
+
471
+	/* Read primary volume descriptor */
472
+	if ( ( rc = sandev_rw ( sandev, lba, count, virt_to_user ( primary ),
473
+				block_read ) ) != 0 ) {
474
+		DBGC ( sandev, "SAN %#02x could not read ISO9660 primary"
475
+		       "volume descriptor: %s\n",
476
+		       sandev->drive, strerror ( rc ) );
477
+		goto err_rw;
478
+	}
479
+
480
+	/* Configure as CD-ROM if applicable */
481
+	if ( memcmp ( primary, &primary_check, sizeof ( primary_check ) ) == 0){
482
+		DBGC ( sandev, "SAN %#02x contains an ISO9660 filesystem; "
483
+		       "treating as CD-ROM\n", sandev->drive );
484
+		sandev->blksize_shift = blksize_shift;
485
+		sandev->is_cdrom = 1;
486
+	}
487
+
488
+ err_rw:
489
+	free ( primary );
490
+ err_alloc:
491
+ invalid_blksize:
492
+	return rc;
493
+}
494
+
495
+/**
496
+ * Allocate SAN device
497
+ *
498
+ * @ret sandev		SAN device, or NULL
499
+ */
500
+struct san_device * alloc_sandev ( struct uri *uri, size_t priv_size ) {
501
+	struct san_device *sandev;
502
+
503
+	/* Allocate and initialise structure */
504
+	sandev = zalloc ( sizeof ( *sandev ) + priv_size );
505
+	if ( ! sandev )
506
+		return NULL;
507
+	ref_init ( &sandev->refcnt, sandev_free );
508
+	sandev->uri = uri_get ( uri );
509
+	intf_init ( &sandev->block, &sandev_block_desc, &sandev->refcnt );
510
+	sandev->block_rc = -EINPROGRESS;
511
+	intf_init ( &sandev->command, &sandev_command_desc, &sandev->refcnt );
512
+	timer_init ( &sandev->timer, sandev_command_expired, &sandev->refcnt );
513
+	sandev->priv = ( ( ( void * ) sandev ) + sizeof ( *sandev ) );
514
+
515
+	return sandev;
516
+}
517
+
518
+/**
519
+ * Register SAN device
520
+ *
521
+ * @v sandev		SAN device
522
+ * @ret rc		Return status code
523
+ */
524
+int register_sandev ( struct san_device *sandev ) {
525
+	int rc;
526
+
527
+	/* Check that drive number is not in use */
528
+	if ( sandev_find ( sandev->drive ) != NULL ) {
529
+		DBGC ( sandev, "SAN %#02x is already in use\n", sandev->drive );
530
+		return -EADDRINUSE;
531
+	}
532
+
533
+	/* Read device capacity */
534
+	if ( ( rc = sandev_command ( sandev, sandev_command_read_capacity,
535
+				     NULL ) ) != 0 )
536
+		return rc;
537
+
538
+	/* Configure as a CD-ROM, if applicable */
539
+	if ( ( rc = sandev_parse_iso9660 ( sandev ) ) != 0 )
540
+		return rc;
541
+
542
+	/* Add to list of SAN devices */
543
+	list_add_tail ( &sandev->list, &san_devices );
544
+
545
+	return 0;
546
+}
547
+
548
+/**
549
+ * Unregister SAN device
550
+ *
551
+ * @v sandev		SAN device
552
+ */
553
+void unregister_sandev ( struct san_device *sandev ) {
554
+
555
+	/* Sanity check */
556
+	assert ( ! timer_running ( &sandev->timer ) );
557
+
558
+	/* Shut down interfaces */
559
+	intfs_shutdown ( 0, &sandev->block, &sandev->command, NULL );
560
+
561
+	/* Remove from list of SAN devices */
562
+	list_del ( &sandev->list );
563
+}

+ 1
- 0
src/include/ipxe/errfile.h 查看文件

@@ -72,6 +72,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
72 72
 #define ERRFILE_blocktrans	       ( ERRFILE_CORE | 0x00200000 )
73 73
 #define ERRFILE_pixbuf		       ( ERRFILE_CORE | 0x00210000 )
74 74
 #define ERRFILE_efi_block	       ( ERRFILE_CORE | 0x00220000 )
75
+#define ERRFILE_sanboot		       ( ERRFILE_CORE | 0x00230000 )
75 76
 
76 77
 #define ERRFILE_eisa		     ( ERRFILE_DRIVER | 0x00000000 )
77 78
 #define ERRFILE_isa		     ( ERRFILE_DRIVER | 0x00010000 )

+ 123
- 1
src/include/ipxe/sanboot.h 查看文件

@@ -12,9 +12,52 @@
12 12
 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
13 13
 
14 14
 #include <ipxe/api.h>
15
+#include <ipxe/refcnt.h>
16
+#include <ipxe/list.h>
17
+#include <ipxe/uri.h>
18
+#include <ipxe/retry.h>
19
+#include <ipxe/blockdev.h>
15 20
 #include <config/sanboot.h>
16 21
 
17
-struct uri;
22
+/** A SAN device */
23
+struct san_device {
24
+	/** Reference count */
25
+	struct refcnt refcnt;
26
+	/** List of SAN devices */
27
+	struct list_head list;
28
+
29
+	/** SAN device URI */
30
+	struct uri *uri;
31
+	/** Drive number */
32
+	unsigned int drive;
33
+
34
+	/** Underlying block device interface */
35
+	struct interface block;
36
+	/** Current device status */
37
+	int block_rc;
38
+
39
+	/** Command interface */
40
+	struct interface command;
41
+	/** Command timeout timer */
42
+	struct retry_timer timer;
43
+	/** Command status */
44
+	int command_rc;
45
+
46
+	/** Raw block device capacity */
47
+	struct block_device_capacity capacity;
48
+	/** Block size shift
49
+	 *
50
+	 * To allow for emulation of CD-ROM access, this represents
51
+	 * the left-shift required to translate from exposed logical
52
+	 * I/O blocks to underlying blocks.
53
+	 */
54
+	unsigned int blksize_shift;
55
+	/** Drive is a CD-ROM */
56
+	int is_cdrom;
57
+
58
+	/** Driver private data */
59
+	void *priv;
60
+};
18 61
 
19 62
 /**
20 63
  * Calculate static inline sanboot API function name
@@ -91,4 +134,83 @@ int san_boot ( unsigned int drive );
91 134
  */
92 135
 int san_describe ( unsigned int drive );
93 136
 
137
+extern struct list_head san_devices;
138
+
139
+/** Iterate over all SAN devices */
140
+#define for_each_sandev( sandev ) \
141
+	list_for_each_entry ( (sandev), &san_devices, list )
142
+
143
+/** There exist some SAN devices
144
+ *
145
+ * @ret existence	Existence of SAN devices
146
+ */
147
+static inline int have_sandevs ( void ) {
148
+	return ( ! list_empty ( &san_devices ) );
149
+}
150
+
151
+/**
152
+ * Get reference to SAN device
153
+ *
154
+ * @v sandev		SAN device
155
+ * @ret sandev		SAN device
156
+ */
157
+static inline __attribute__ (( always_inline )) struct san_device *
158
+sandev_get ( struct san_device *sandev ) {
159
+	ref_get ( &sandev->refcnt );
160
+	return sandev;
161
+}
162
+
163
+/**
164
+ * Drop reference to SAN device
165
+ *
166
+ * @v sandev		SAN device
167
+ */
168
+static inline __attribute__ (( always_inline )) void
169
+sandev_put ( struct san_device *sandev ) {
170
+	ref_put ( &sandev->refcnt );
171
+}
172
+
173
+/**
174
+ * Calculate SAN device block size
175
+ *
176
+ * @v sandev		SAN device
177
+ * @ret blksize		Sector size
178
+ */
179
+static inline size_t sandev_blksize ( struct san_device *sandev ) {
180
+	return ( sandev->capacity.blksize << sandev->blksize_shift );
181
+}
182
+
183
+/**
184
+ * Calculate SAN device capacity
185
+ *
186
+ * @v sandev		SAN device
187
+ * @ret blocks		Number of blocks
188
+ */
189
+static inline uint64_t sandev_capacity ( struct san_device *sandev ) {
190
+	return ( sandev->capacity.blocks >> sandev->blksize_shift );
191
+}
192
+
193
+/**
194
+ * Check if SAN device needs to be reopened
195
+ *
196
+ * @v sandev		SAN device
197
+ * @ret needs_reopen	SAN device needs to be reopened
198
+ */
199
+static inline int sandev_needs_reopen ( struct san_device *sandev ) {
200
+	return ( sandev->block_rc != 0 );
201
+}
202
+
203
+extern struct san_device * sandev_find ( unsigned int drive );
204
+extern int sandev_reopen ( struct san_device *sandev );
205
+extern int sandev_reset ( struct san_device *sandev );
206
+extern int sandev_rw ( struct san_device *sandev, uint64_t lba,
207
+		       unsigned int count, userptr_t buffer,
208
+		       int ( * block_rw ) ( struct interface *control,
209
+					    struct interface *data,
210
+					    uint64_t lba, unsigned int count,
211
+					    userptr_t buffer, size_t len ) );
212
+extern struct san_device * alloc_sandev ( struct uri *uri, size_t priv_size );
213
+extern int register_sandev ( struct san_device *sandev );
214
+extern void unregister_sandev ( struct san_device *sandev );
215
+
94 216
 #endif /* _IPXE_SANBOOT_H */

正在加载...
取消
保存