Import writing part of the UDF file system making optical media like CD's

and DVD's behave like floppy discs. Writing is supported upto and including
version 2.01; version 2.50 and 2.60 will follow.

Also extending the UDF implementation to support symbolic links and
hardlinks.

Added are the mmcformat(8) tool to format rewritable CD/DVD discs and
newfs_udf(8).

Limitations:
        all operations can be performed on the file system though the
        sheduling is currently optimised for archiving workloads.

        mv(1)/rename(2) is currently only implemented for non-directories.
This commit is contained in:
reinoud 2008-05-14 16:49:47 +00:00
parent 20275ee931
commit e979c658c9
36 changed files with 17831 additions and 1680 deletions

View File

@ -1,4 +1,4 @@
# $NetBSD: mi,v 1.746 2008/05/11 18:01:46 joerg Exp $
# $NetBSD: mi,v 1.747 2008/05/14 16:49:47 reinoud Exp $
#
# Note: Don't delete entries from here - mark them as "obsolete" instead,
# unless otherwise stated below.
@ -216,6 +216,7 @@
./sbin/newfs_lfs base-sysutil-root
./sbin/newfs_msdos base-sysutil-root
./sbin/newfs_sysvbfs base-sysutil-root
./sbin/newfs_udf base-sysutil-root
./sbin/newlfs base-obsolete obsolete
./sbin/nfsd base-obsolete obsolete
./sbin/nfsiod base-obsolete obsolete
@ -1170,6 +1171,7 @@
./usr/sbin/mknetid base-nis-bin yp
./usr/sbin/mld6query base-netutil-bin use_inet6
./usr/sbin/mlxctl base-sysutil-bin
./usr/sbin/mmcformat base-sysutil-bin
./usr/sbin/mopa.out base-obsolete obsolete
./usr/sbin/mopchk base-bootserver-bin
./usr/sbin/mopcopy base-bootserver-bin

View File

@ -1,4 +1,4 @@
# $NetBSD: mi,v 1.1069 2008/05/11 18:01:46 joerg Exp $
# $NetBSD: mi,v 1.1070 2008/05/14 16:49:47 reinoud Exp $
#
# Note: don't delete entries from here - mark them as "obsolete" instead.
#
@ -2173,6 +2173,7 @@
./usr/share/man/cat8/mknod.0 man-sysutil-catman .cat
./usr/share/man/cat8/mld6query.0 man-netutil-catman use_inet6,.cat
./usr/share/man/cat8/mlxctl.0 man-sysutil-catman .cat
./usr/share/man/cat8/mmcformat.0 man-sysutil-catman .cat
./usr/share/man/cat8/mmeye/MAKEDEV.0 man-obsolete obsolete
./usr/share/man/cat8/mmeye/makedev.0 man-obsolete obsolete
./usr/share/man/cat8/modload.0 man-sysutil-catman .cat
@ -2246,6 +2247,7 @@
./usr/share/man/cat8/newfs_lfs.0 man-sysutil-catman .cat
./usr/share/man/cat8/newfs_msdos.0 man-sysutil-catman .cat
./usr/share/man/cat8/newfs_sysvbfs.0 man-sysutil-catman .cat
./usr/share/man/cat8/newfs_udf.0 man-sysutil-catman .cat
./usr/share/man/cat8/newlfs.0 man-obsolete obsolete
./usr/share/man/cat8/news68k/MAKEDEV.0 man-obsolete obsolete
./usr/share/man/cat8/news68k/makedev.0 man-obsolete obsolete
@ -4723,6 +4725,7 @@
./usr/share/man/man8/mknod.8 man-sysutil-man .man
./usr/share/man/man8/mld6query.8 man-netutil-man use_inet6,.man
./usr/share/man/man8/mlxctl.8 man-sysutil-man .man
./usr/share/man/man8/mmcformat.8 man-sysutil-man .man
./usr/share/man/man8/mmeye/MAKEDEV.8 man-obsolete obsolete
./usr/share/man/man8/mmeye/makedev.8 man-obsolete obsolete
./usr/share/man/man8/modload.8 man-sysutil-man .man
@ -4796,6 +4799,7 @@
./usr/share/man/man8/newfs_lfs.8 man-sysutil-man .man
./usr/share/man/man8/newfs_msdos.8 man-sysutil-man .man
./usr/share/man/man8/newfs_sysvbfs.8 man-sysutil-man .man
./usr/share/man/man8/newfs_udf.8 man-sysutil-man .man
./usr/share/man/man8/newlfs.8 man-obsolete obsolete
./usr/share/man/man8/news68k/MAKEDEV.8 man-obsolete obsolete
./usr/share/man/man8/news68k/makedev.8 man-obsolete obsolete

View File

@ -1,4 +1,4 @@
# $NetBSD: Makefile,v 1.109 2008/02/09 19:32:28 jmmv Exp $
# $NetBSD: Makefile,v 1.110 2008/05/14 16:49:47 reinoud Exp $
# @(#)Makefile 8.5 (Berkeley) 3/31/94
# Not ported: XNSrouted enpload scsiformat startslip
@ -24,6 +24,7 @@ SUBDIR+= newfs fsck_ffs fsdb dump restore clri tunefs
SUBDIR+= newfs_lfs fsck_lfs dump_lfs resize_lfs
SUBDIR+= newfs_msdos fsck_msdos
SUBDIR+= newfs_sysvbfs
SUBDIR+= newfs_udf
SUBDIR+= mount_ados
SUBDIR+= mount_cd9660
SUBDIR+= mount_efs

18
sbin/newfs_udf/Makefile Normal file
View File

@ -0,0 +1,18 @@
# $NetBSD: Makefile,v 1.1 2008/05/14 16:49:48 reinoud Exp $
.include <bsd.own.mk>
WARNS= 4
PROG= newfs_udf
MAN= newfs_udf.8
SRCS= newfs_udf.c udf_create.o udf_osta.o fattr.c
MOUNT= ${NETBSDSRCDIR}/sbin/mount
KUDF= ${NETBSDSRCDIR}/sys/fs/udf
CPPFLAGS+= -I${MOUNT} -I${KUDF} -I${NETBSDSRCDIR}/sys
.PATH: ${MOUNT} ${KUDF}
DPADD+=${LIBUTIL}
LDADD+=-lutil
.include <bsd.prog.mk>

144
sbin/newfs_udf/newfs_udf.8 Normal file
View File

@ -0,0 +1,144 @@
.\" $NetBSD: newfs_udf.8,v 1.1 2008/05/14 16:49:48 reinoud Exp $
.\"
.\" Copyright (c) 2008 Reinoud Zandijk
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in
.\" the documentation and/or other materials provided with the
.\" distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
.\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY
.\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
.\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
.\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\"
.Dd May 9, 2008
.Dt NEWFS_UDF 8
.Os
.Sh NAME
.Nm newfs_udf
.Nd construct a new UDF file system
.Sh SYNOPSIS
.Nm
.Op Fl c
.Op Fl F
.Op Fl L Ar loglabel
.Op Fl M
.Op Fl v Ar min_udf
.Op Fl V Ar max_udf
.Op Fl P Ar discid
.Op Fl s Ar size
.Op Fl S Ar setlabel
.Op Fl t Ar gmtoff
.Ar special
.Sh DESCRIPTION
The
.Nm
utility creates an UDF file system on device
.Ar special
suitable for the media currently inserted.
.Pp
The options are as follow:
.Bl -tag -width indent
.It Fl c
Perform a crude surface check first to weed out disc faults on rewritable
media.
.It Fl F
Force file system construction on non-empty recordable media.
.It Fl L Ar loglabel
Set the disc logical label to the specified
.Ar loglabel .
.It Fl M
Disable metadata partition flavour selection.
.It Fl v Ar min_udf
Select
.Ar min_udf
as the minimum UDF version to be supported. Notation "0x201" for UDF version
2.01.
.It Fl V Ar max_udf
Select
.Ar max_udf
as the maximum UDF version to be supported. Notation "0x250" for UDF version
2.50.
.It Fl P Ar discid
Set the phyisical disc label to the specified
.Ar discid .
For strict conformance and interchange dont set this manually.
.It Fl s Ar size
Ignored for now.
.It Fl S Ar setlabel
Set the disc set label to the specified
.Ar setlabel .
For strict conformance and interchange dont set this manually.
.It Fl t Ar gmtoff
Use the specified
.Ar gmtoff
as gmt time offset for recording times on the disc.
.El
.Sh NOTES
The UDF file system is defined for the entire optical medium. It can only
function on the entire CD/DVD/BD so the raw partition has to be specified for
read/write actions. For
.Nm
this means specifying the raw device with the raw partition. i.e.
.Pa /dev/rcd0d
or
.Pa /dev/rcd0c.
.Pp
Some rewritable optical media needs to be formatted first before it can be
used by UDF. This can be done using
.Xr mmcformat 8 .
.Pp
The default UDF version is version 2.01 that can be specified if required
as "0x201".
.Sh EXAMPLES
.Bd -literal -offset indent
newfs_udf -S "Encyclopedia" -L "volume 2" -P "copy-nr-1" /dev/rcd0d
.Ed
.Pp
Create a file system, using the specified names on the device
.Pa /dev/rcd0d
with the default UDF version.
.Pp
.Bd -literal -offset indent
dd if=/dev/zero of=bigdisk.2048.udf seek=9999999 count=1
vnconfig -c vnd0 bigdisk.2048.udf 2048/1/1/1
newfs_udf -L bigdisk /dev/rvnd0d
.Ed
.Pp
Create a 4.8 Gb sparse file and configure it using
.Xr vnconfig 8
to be a 2048 sector size disc and create a new UDF file system on
.Pa /dev/rvnd0d .
.Bd -literal -offset indent
newfs_udf -L "My USB stick" /dev/rsd0d
.Ed
.Pp
Create a new UDF file system on the inserted USB stick using its `native'
sectorsize of 512.
.Sh SEE ALSO
.Xr disktab 5 ,
.Xr disklabel 8 ,
.Xr mmcformat 8 ,
.Xr newfs 8
.Sh HISTORY
The
.Nm
command first appeared in
.Nx 5.0 .
.Sh AUTHORS
.An Reinoud Zandijk Aq reinoud@NetBSD.org .

1456
sbin/newfs_udf/newfs_udf.c Normal file

File diff suppressed because it is too large Load Diff

1513
sbin/newfs_udf/udf_create.c Normal file

File diff suppressed because it is too large Load Diff

234
sbin/newfs_udf/udf_create.h Normal file
View File

@ -0,0 +1,234 @@
/* $NetBSD: udf_create.h,v 1.1 2008/05/14 16:49:48 reinoud Exp $ */
/*
* Copyright (c) 2006, 2008 Reinoud Zandijk
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef _FS_UDF_UDF_CREATE_H_
#define _FS_UDF_UDF_CREATE_H_
#include <sys/types.h>
#include <fs/udf/ecma167-udf.h>
#include "udf_bswap.h"
#include "udf_osta.h"
/* format flags indicating properties of disc to create */
#define FORMAT_WRITEONCE 0x00001
#define FORMAT_SEQUENTIAL 0x00002
#define FORMAT_REWRITABLE 0x00004
#define FORMAT_SPARABLE 0x00008
#define FORMAT_META 0x00010
#define FORMAT_LOW 0x00020
#define FORMAT_VAT 0x00040
#define FORMAT_WORM 0x00080
#define FORMAT_TRACK512 0x00100
#define FORMAT_INVALID 0x00200
#define FORMAT_FLAGBITS \
"\10\1WRITEONCE\2SEQUENTIAL\3REWRITABLE\4SPARABLE\5META\6LOW" \
"\7VAT\10WORM\11TRACK512\12INVALID"
/* structure space */
#define UDF_ANCHORS 4 /* 256, 512, N-256, N */
#define UDF_PARTITIONS 4 /* overkill */
#define UDF_PMAPS 4 /* overkill */
/* misc constants */
#define UDF_MAX_NAMELEN 255 /* as per SPEC */
/* translation constants */
#define UDF_VTOP_RAWPART UDF_PMAPS /* [0..UDF_PMAPS> are normal */
/* virtual to physical mapping types */
#define UDF_VTOP_TYPE_RAW 0
#define UDF_VTOP_TYPE_UNKNOWN 0
#define UDF_VTOP_TYPE_PHYS 1
#define UDF_VTOP_TYPE_VIRT 2
#define UDF_VTOP_TYPE_SPARABLE 3
#define UDF_VTOP_TYPE_META 4
#define UDF_TRANS_ZERO ((uint64_t) -1)
#define UDF_TRANS_UNMAPPED ((uint64_t) -2)
#define UDF_TRANS_INTERN ((uint64_t) -3)
#define UDF_MAX_SECTOR ((uint64_t) -10) /* high water mark */
/* handys */
#define UDF_ROUNDUP(val, gran) \
((gran) * (((val) + (gran)-1) / (gran)))
#define UDF_ROUNDDOWN(val, gran) \
((gran) * (((val)) / (gran)))
/* disc offsets for various structures and their sizes */
struct udf_disclayout {
uint32_t wrtrack_skew;
uint32_t iso9660_vrs;
uint32_t anchors[UDF_ANCHORS];
uint32_t vds_size, vds1, vds2;
uint32_t lvis_size, lvis;
uint32_t first_lba, last_lba;
uint32_t sector_size;
uint32_t blockingnr, align_blockingnr, sparable_blockingnr;
uint32_t bitmap_dscr_size;
uint32_t unalloc_space, freed_space;
uint32_t sparable_blocks;
uint32_t sparable_area, sparable_area_size;
uint32_t sparing_table_dscr_lbas;
uint32_t spt_1, spt_2;
uint32_t fsd, rootdir, vat;
/* partition */
uint32_t part_start_lba, part_size_lbas;
};
/* all info about discs and descriptors building */
struct udf_create_context {
/* descriptors */
int dscrver; /* 2 or 3 */
int min_udf; /* hex */
int max_udf; /* hex */
int serialnum; /* format serialno */
int gmtoff; /* in minutes */
/* XXX to layout? */
int sector_size;
/* identification */
char *logvol_name;
char *primary_name;
char *volset_name;
char *fileset_name;
char const *app_name;
char const *impl_name;
int app_version_main;
int app_version_sub;
/* building */
int vds_seq; /* for building functions */
int unique_id; /* only first few are used */
/* constructed structures */
struct anchor_vdp *anchors[UDF_ANCHORS]; /* anchors to VDS */
struct pri_vol_desc *primary_vol; /* identification */
struct logvol_desc *logical_vol; /* main mapping v->p */
struct unalloc_sp_desc *unallocated; /* free UDF space */
struct impvol_desc *implementation; /* likely reduntant */
struct logvol_int_desc *logvol_integrity; /* current integrity */
struct part_desc *partitions[UDF_PARTITIONS]; /* partitions */
/* XXX to layout? */
int data_part;
int metadata_part;
/* derived; points *into* other structures */
struct udf_logvol_info *logvol_info; /* inside integrity */
/* fileset and root directories */
struct fileset_desc *fileset_desc; /* normally one */
/* logical to physical translations */
int vtop[UDF_PMAPS+1]; /* vpartnr trans */
int vtop_tp[UDF_PMAPS+1]; /* type of trans */
/* sparable */
struct udf_sparing_table*sparing_table; /* replacements */
/* lvint */
int num_files;
int num_directories;
uint32_t part_size[UDF_PARTITIONS];
uint32_t part_free[UDF_PARTITIONS];
struct space_bitmap_desc*part_unalloc_bits[UDF_PARTITIONS];
struct space_bitmap_desc*part_freed_bits [UDF_PARTITIONS];
};
/* globals */
extern struct udf_create_context context;
extern struct udf_disclayout layout;
/* prototypes */
void udf_init_create_context(void);
int udf_calculate_disc_layout(int format_flags, int min_udf,
uint32_t wrtrack_skew,
uint32_t first_lba, uint32_t last_lba,
uint32_t sector_size, uint32_t blockingnr,
uint32_t sparable_blocks);
void udf_osta_charset(struct charspec *charspec);
void udf_encode_osta_id(char *osta_id, uint16_t len, char *text);
void udf_set_regid(struct regid *regid, char const *name);
void udf_add_domain_regid(struct regid *regid);
void udf_add_udf_regid(struct regid *regid);
void udf_add_impl_regid(struct regid *regid);
void udf_add_app_regid(struct regid *regid);
int udf_validate_tag_sum(union dscrptr *dscr);
int udf_validate_tag_and_crc_sums(union dscrptr *dscr);
void udf_set_timestamp_now(struct timestamp *timestamp);
void udf_inittag(struct desc_tag *tag, int tagid, uint32_t loc);
int udf_create_anchor(int num);
void udf_create_terminator(union dscrptr *dscr, uint32_t loc);
int udf_create_primaryd(void);
int udf_create_partitiond(int part_num, int part_accesstype);
int udf_create_unalloc_spaced(void);
int udf_create_sparing_tabled(void);
int udf_create_space_bitmap(struct space_bitmap_desc **sbdp);
int udf_create_logical_dscr(int format_flags);
int udf_create_impvold(char *field1, char *field2, char *field3);
int udf_create_fsd(void);
int udf_create_lvintd(int type);
void udf_update_lvintd(int type);
int udf_register_bad_block(uint32_t location);
void udf_mark_allocated(uint32_t start_lb, int partnr, uint32_t blocks);
int udf_create_new_fe(struct file_entry **fep, int file_type,
struct long_ad *parent_icb);
int udf_create_new_efe(struct extfile_entry **efep, int file_type,
struct long_ad *parent_icb);
int udf_create_new_rootdir(union dscrptr **dscr);
int udf_create_new_VAT(union dscrptr **vat_dscr);
#endif /* _FS_UDF_UDF_CREATE_H_ */

View File

@ -1,7 +1,7 @@
/* $NetBSD: ecma167-udf.h,v 1.7 2007/12/25 18:33:44 perry Exp $ */
/* $NetBSD: ecma167-udf.h,v 1.8 2008/05/14 16:49:48 reinoud Exp $ */
/*-
* Copyright (c) 2003, 2004, 2005, 2006 Reinoud Zandijk <reinoud@netbsd.org>
* Copyright (c) 2003, 2004, 2005, 2006, 2008 Reinoud Zandijk
* Copyright (c) 2001, 2002 Scott Long <scottl@freebsd.org>
* All rights reserved.
*
@ -101,7 +101,7 @@ enum {
TAGID_FSD = 256,
TAGID_FID = 257,
TAGID_ALLOCEXTENT = 258,
TAGID_INDIRECT_ENTRY = 259,
TAGID_INDIRECTENTRY = 259,
TAGID_ICB_TERM = 260,
TAGID_FENTRY = 261,
TAGID_EXTATTR_HDR = 262,
@ -209,6 +209,7 @@ union icb {
#define UDF_EXT_REDIRECT (3<<30)
#define UDF_EXT_FLAGS(len) ((len) & (3<<30))
#define UDF_EXT_LEN(len) ((len) & ((1<<30)-1))
#define UDF_EXT_MAXLEN ((1<<30)-1)
/* Character set spec [1/7.2.1] */
@ -218,6 +219,21 @@ struct charspec {
} __packed;
struct pathcomp {
uint8_t type;
uint8_t l_ci;
uint16_t comp_filever;
uint8_t ident[256];
} __packed;
#define UDF_PATH_COMP_SIZE 4
#define UDF_PATH_COMP_RESERVED 0
#define UDF_PATH_COMP_ROOT 1
#define UDF_PATH_COMP_MOUNTROOT 2
#define UDF_PATH_COMP_PARENTDIR 3
#define UDF_PATH_COMP_CURDIR 4
#define UDF_PATH_COMP_NAME 5
/* Timestamp [1/7.3] */
struct timestamp {
uint16_t type_tz;
@ -629,7 +645,7 @@ struct fileid_desc {
uint8_t l_fi; /* Length of file identifier area */
struct long_ad icb;
uint16_t l_iu; /* Length of implementation use area */
uint8_t data[1];
uint8_t data[0];
} __packed;
#define UDF_FID_SIZE 38
#define UDF_FILE_CHAR_VIS (1 << 0) /* Invisible */
@ -764,6 +780,7 @@ struct extfile_entry {
uint32_t l_ad; /* Length of allocation descriptors */
uint8_t data[1];
} __packed;
#define UDF_EXTFENTRY_SIZE 216
/* Indirect entry [ecma 48.7] */
@ -774,7 +791,7 @@ struct indirect_entry {
} __packed;
/* Allocation extent descritor [ecma 48.5] */
/* Allocation extent descriptor [ecma 48.5] */
struct alloc_ext_entry {
struct desc_tag tag;
uint32_t prev_entry;
@ -806,13 +823,5 @@ union dscrptr {
} __packed;
/* Useful defines */
#define GETICB(ad_type, fentry, offset) \
(struct ad_type *)&fentry->data[offset]
#define GETICBLEN(ad_type, icb) ((struct ad_type *)(icb))->len
#endif /* !_FS_UDF_ECMA167_UDF_H_ */

View File

@ -1,4 +1,4 @@
# $NetBSD: files.udf,v 1.1 2006/02/02 15:19:15 reinoud Exp $
# $NetBSD: files.udf,v 1.2 2008/05/14 16:49:48 reinoud Exp $
deffs fs_udf.h UDF
@ -6,4 +6,12 @@ file fs/udf/udf_osta.c udf
file fs/udf/udf_vfsops.c udf
file fs/udf/udf_vnops.c udf
file fs/udf/udf_subr.c udf
file fs/udf/udf_readwrite.c udf
file fs/udf/udf_strat_bootstrap.c udf
file fs/udf/udf_strat_sequential.c udf
file fs/udf/udf_strat_direct.c udf
file fs/udf/udf_strat_rmw.c udf
file fs/udf/udf_allocation.c udf
defflag opt_udf.h UDF_READWRITE

View File

@ -1,7 +1,7 @@
/* $NetBSD: udf.h,v 1.10 2007/10/10 20:42:25 ad Exp $ */
/* $NetBSD: udf.h,v 1.11 2008/05/14 16:49:48 reinoud Exp $ */
/*
* Copyright (c) 2006 Reinoud Zandijk
* Copyright (c) 2006, 2008 Reinoud Zandijk
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -12,13 +12,6 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the
* NetBSD Project. See http://www.NetBSD.org/ for
* information about NetBSD.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
@ -43,28 +36,41 @@
#include "udf_osta.h"
#include "ecma167-udf.h"
#include <sys/cdio.h>
#include <sys/bufq.h>
#include <sys/disk.h>
#include <sys/kthread.h>
#include <miscfs/genfs/genfs_node.h>
/* TODO make `udf_verbose' set by sysctl */
/* debug section */
extern int udf_verbose;
/* initial value of udf_verbose */
#define UDF_DEBUGGING 0x000
/* undefine UDF_COMPLETE_DELETE to need `purge'; but purge is not implemented */
#define UDF_COMPLETE_DELETE
/* debug categories */
#define UDF_DEBUG_VOLUMES 0x001
#define UDF_DEBUG_LOCKING 0x002
#define UDF_DEBUG_NODE 0x004
#define UDF_DEBUG_LOOKUP 0x008
#define UDF_DEBUG_READDIR 0x010
#define UDF_DEBUG_FIDS 0x020
#define UDF_DEBUG_DESCRIPTOR 0x040
#define UDF_DEBUG_TRANSLATE 0x080
#define UDF_DEBUG_STRATEGY 0x100
#define UDF_DEBUG_READ 0x200
#define UDF_DEBUG_CALL 0x400
#define UDF_DEBUG_NOTIMPL UDF_DEBUG_CALL
#define UDF_DEBUG_VOLUMES 0x00001
#define UDF_DEBUG_LOCKING 0x00002
#define UDF_DEBUG_NODE 0x00004
#define UDF_DEBUG_LOOKUP 0x00008
#define UDF_DEBUG_READDIR 0x00010
#define UDF_DEBUG_FIDS 0x00020
#define UDF_DEBUG_DESCRIPTOR 0x00040
#define UDF_DEBUG_TRANSLATE 0x00080
#define UDF_DEBUG_STRATEGY 0x00100
#define UDF_DEBUG_READ 0x00200
#define UDF_DEBUG_WRITE 0x00400
#define UDF_DEBUG_CALL 0x00800
#define UDF_DEBUG_ATTR 0x01000
#define UDF_DEBUG_EXTATTR 0x02000
#define UDF_DEBUG_ALLOC 0x04000
#define UDF_DEBUG_ADWLK 0x08000
#define UDF_DEBUG_NOTIMPL 0x10000
#define UDF_DEBUG_SHEDULE 0x20000
#define UDF_DEBUG_SYNC 0x40000
#define UDF_DEBUG_PARANOIA 0x80000
/* initial value of udf_verbose */
#define UDF_DEBUGGING 0
#ifdef DEBUG
@ -101,21 +107,34 @@ SYSCTL_SETUP_PROTO(sysctl_vfs_udf_setup);
/* DON'T change these: they identify 13thmonkey's UDF implementation */
#define APP_NAME "*NetBSD UDF"
#define APP_VERSION_MAIN 1
#define APP_VERSION_SUB 0
#define IMPL_NAME "*13thMonkey.org"
#define APP_VERSION_MAIN 0
#define APP_VERSION_SUB 4
#define IMPL_NAME "*NetBSD kernel UDF"
/* Configuration values */
#define UDF_INODE_HASHBITS 10
#define UDF_INODE_HASHSIZE (1<<UDF_INODE_HASHBITS)
#define UDF_INODE_HASHMASK (UDF_INODE_HASHSIZE - 1)
#define UDF_ECCBUF_HASHBITS 10
#define UDF_ECCBUF_HASHSIZE (1<<UDF_ECCBUF_HASHBITS)
#define UDF_ECCBUF_HASHMASK (UDF_ECCBUF_HASHSIZE -1)
#define UDF_ECCLINE_MAXFREE 10 /* picked */
#define UDF_ECCLINE_MAXBUSY 100 /* picked */
#define UDF_MAX_MAPPINGS (MAXPHYS/DEV_BSIZE) /* 128 */
#define UDF_VAT_CHUNKSIZE (64*1024) /* picked */
#define UDF_SYMLINKBUFLEN (64*1024) /* picked */
/* structure space */
#define UDF_ANCHORS 4 /* 256, 512, N-256, N */
#define UDF_PARTITIONS 4 /* overkill */
#define UDF_PMAPS 4 /* overkill */
#define UDF_PMAPS 5 /* overkill */
#define UDF_LVDINT_SEGMENTS 100 /* big overkill */
#define UDF_LVINT_LOSSAGE 4 /* lose 2 openings */
#define UDF_MAX_ALLOC_EXTENTS 10 /* overkill */
/* constants */
@ -126,14 +145,113 @@ SYSCTL_SETUP_PROTO(sysctl_vfs_udf_setup);
#define UDF_MAX_SECTOR ((uint64_t) -10) /* high water mark */
/* RW content hint for allocation and other purposes */
#define UDF_C_PROCESSED 0 /* not relevant */
#define UDF_C_USERDATA 1 /* all but userdata is metadata */
//#define UDF_C_METADATA 2 /* unspecified metadata */
#define UDF_C_DSCR 3 /* update sectornr and CRC */
#define UDF_C_NODE 4 /* file/dir node, update sectornr and CRC */
#define UDF_C_EXTATTRS 5 /* dunno what to do yet */
#define UDF_C_FIDS 6 /* update all contained fids */
/* use unused b_freelistindex for our UDF_C_TYPE */
#define b_udf_c_type b_freelistindex
/* virtual to physical mapping types */
#define UDF_VTOP_RAWPART UDF_PMAPS /* [0..UDF_PMAPS> are normal */
#define UDF_VTOP_TYPE_RAW 0
#define UDF_VTOP_TYPE_UNKNOWN 0
#define UDF_VTOP_TYPE_PHYS 1
#define UDF_VTOP_TYPE_VIRT 2
#define UDF_VTOP_TYPE_SPARABLE 3
#define UDF_VTOP_TYPE_META 4
/* allocation strategies */
#define UDF_ALLOC_SEQUENTIAL 1 /* linear on NWA */
#define UDF_ALLOC_VAT 2 /* VAT handling */
#define UDF_ALLOC_SPACEMAP 3 /* spacemaps */
#define UDF_ALLOC_METABITMAP 4 /* metadata bitmap */
#define UDF_ALLOC_METASEQUENTIAL 5 /* in chunks seq., nodes not seq */
#define UDF_ALLOC_RELAXEDSEQUENTIAL 6 /* only nodes not seq. */
/* logical volume open/close actions */
#define UDF_OPEN_SESSION 0x01 /* if needed writeout VRS + VDS */
#define UDF_CLOSE_SESSION 0x02 /* close session after writing VAT */
#define UDF_WRITE_VAT 0x04 /* sequential VAT filesystem */
#define UDF_WRITE_LVINT 0x08 /* write out open lvint */
#define UDF_WRITE_PART_BITMAPS 0x10 /* write out partition space bitmaps */
#define UDF_APPENDONLY_LVINT 0x20 /* no shifting, only appending */
#define UDFLOGVOL_BITS "\20\1OPENSESSION\2CLOSESESSION\3WRITEVAT\4WRITELVINT"\
"\5APPENDONLY"
/* logical volume error handling actions */
#define UDF_UPDATE_TRACKINFO 0x01 /* update trackinfo and re-shedule */
#define UDF_REMAP_BLOCK 0x02 /* remap the failing block length */
#define UDFONERROR_BITS "\20\1UPDATE_TRACKINFO\2REMAP_BLOCK"
/* readdir cookies */
#define UDF_DIRCOOKIE_DOT 1
/* malloc pools */
MALLOC_DECLARE(M_UDFMNT);
MALLOC_DECLARE(M_UDFVOLD);
MALLOC_DECLARE(M_UDFTEMP);
struct pool udf_node_pool;
struct udf_node;
struct udf_strategy;
struct udf_lvintq {
uint32_t start;
uint32_t end;
uint32_t pos;
uint32_t wpos;
};
struct udf_bitmap {
uint8_t *blob; /* allocated */
uint8_t *bits; /* bits themselves */
uint8_t *pages; /* dirty pages */
uint32_t max_offset; /* in bits */
uint32_t data_pos; /* position in data */
uint32_t metadata_pos; /* .. in metadata */
};
struct udf_strat_args {
struct udf_mount *ump;
struct udf_node *udf_node;
struct long_ad *icb;
union dscrptr *dscr;
struct buf *nestbuf;
kauth_cred_t cred;
int waitfor;
};
struct udf_strategy {
int (*create_logvol_dscr) (struct udf_strat_args *args);
void (*free_logvol_dscr) (struct udf_strat_args *args);
int (*read_logvol_dscr) (struct udf_strat_args *args);
int (*write_logvol_dscr) (struct udf_strat_args *args);
void (*queuebuf) (struct udf_strat_args *args);
void (*discstrat_init) (struct udf_strat_args *args);
void (*discstrat_finish) (struct udf_strat_args *args);
};
extern struct udf_strategy udf_strat_bootstrap;
extern struct udf_strategy udf_strat_sequential;
extern struct udf_strategy udf_strat_direct;
extern struct udf_strategy udf_strat_rmw;
/* pre cleanup */
struct udf_mount {
@ -142,7 +260,8 @@ struct udf_mount {
struct mmc_discinfo discinfo;
struct udf_args mount_args;
/* read in structures */
/* format descriptors */
kmutex_t logvol_mutex;
struct anchor_vdp *anchors[UDF_ANCHORS]; /* anchors to VDS */
struct pri_vol_desc *primary_vol; /* identification */
struct logvol_desc *logical_vol; /* main mapping v->p */
@ -150,113 +269,147 @@ struct udf_mount {
struct impvol_desc *implementation; /* likely reduntant */
struct logvol_int_desc *logvol_integrity; /* current integrity */
struct part_desc *partitions[UDF_PARTITIONS]; /* partitions */
/* derived; points *into* other structures */
/* logvol_info is derived; points *into* other structures */
struct udf_logvol_info *logvol_info; /* integrity descr. */
/* fileset and root directories */
struct fileset_desc *fileset_desc; /* normally one */
/* tracing logvol integrity history */
struct udf_lvintq lvint_trace[UDF_LVDINT_SEGMENTS];
int lvopen; /* logvol actions */
int lvclose; /* logvol actions */
/* disc allocation / writing method */
int lvreadwrite; /* bits */
int data_alloc; /* all userdata */
int meta_alloc; /* all metadata */
int data_part;
int metadata_part;
kmutex_t allocate_mutex;
/* logical to physical translations */
int vtop[UDF_PMAPS+1]; /* vpartnr trans */
int vtop_tp[UDF_PMAPS+1]; /* type of trans */
/* sequential track info */
struct mmc_trackinfo data_track;
struct mmc_trackinfo metadata_track;
/* VAT */
uint32_t first_possible_vat_location;
uint32_t last_possible_vat_location;
uint32_t vat_table_alloc_length;
uint32_t vat_entries;
uint32_t vat_offset; /* offset in table */
uint8_t *vat_table; /* read in data */
uint32_t vat_last_free_lb; /* last free lb_num */
uint32_t vat_table_len;
uint32_t vat_table_alloc_len;
uint8_t *vat_table;
uint8_t *vat_pages; /* TODO */
struct udf_node *vat_node; /* system node */
/* space bitmaps */
struct space_bitmap_desc*part_unalloc_dscr[UDF_PARTITIONS];
struct space_bitmap_desc*part_freed_dscr [UDF_PARTITIONS];
struct udf_bitmap part_unalloc_bits[UDF_PARTITIONS];
struct udf_bitmap part_freed_bits [UDF_PARTITIONS];
/* sparable */
uint32_t sparable_packet_len;
uint32_t sparable_packet_size;
uint32_t packet_size;
struct udf_sparing_table*sparing_table;
/* meta */
struct udf_node *metadata_file;
struct udf_node *metadatamirror_file;
struct udf_node *metadatabitmap_file;
struct udf_node *metadata_node; /* system node */
struct udf_node *metadatamirror_node; /* system node */
struct udf_node *metadatabitmap_node; /* system node */
struct udf_bitmap metadata_bitmap; /* TODO : readin */
/* disc allocation */
int data_alloc, meta_alloc; /* allocation scheme */
struct mmc_trackinfo datatrack;
struct mmc_trackinfo metadatatrack;
/* TODO free space and usage per partition */
/* ... [UDF_PARTITIONS]; */
/* hash table to lookup ino_t -> udf_node */
LIST_HEAD(, udf_node) udf_nodes[UDF_INODE_HASHSIZE];
/* allocation pool for udf_node's descriptors */
struct pool *desc_pool;
/* locks */
/* hash table to lookup icb -> udf_node and sorted list for sync */
kmutex_t ihash_lock;
kmutex_t get_node_lock;
LIST_HEAD(, udf_node) udf_nodes[UDF_INODE_HASHSIZE];
LIST_HEAD(, udf_node) sorted_udf_nodes; /* sorted sync list */
/* syncing */
int syncing; /* are we syncing? */
kcondvar_t dirtynodes_cv; /* sleeping on sync */
/* late allocation */
uint32_t uncomitted_lb; /* for free space */
struct long_ad *la_node_ad_cpy; /* issue buf */
uint64_t *la_lmapping, *la_pmapping; /* issue buf */
/* lists */
STAILQ_HEAD(, udf_node) dirty_nodes;
STAILQ_HEAD(udfmntpts, udf_mount) all_udf_mntpnts;
/* device strategy */
struct udf_strategy *strategy;
void *strategy_private;
};
#define UDF_VTOP_RAWPART UDF_PMAPS /* [0..UDF_PMAPS> are normal */
/* virtual to physical mapping types */
#define UDF_VTOP_TYPE_RAW 0
#define UDF_VTOP_TYPE_UNKNOWN 0
#define UDF_VTOP_TYPE_PHYS 1
#define UDF_VTOP_TYPE_VIRT 2
#define UDF_VTOP_TYPE_SPARABLE 3
#define UDF_VTOP_TYPE_META 4
/* allocation strategies */
#define UDF_ALLOC_SPACEMAP 1 /* spacemaps */
#define UDF_ALLOC_SEQUENTIAL 2 /* linear on NWA */
#define UDF_ALLOC_VAT 3 /* VAT handling */
#define UDF_ALLOC_METABITMAP 4 /* metadata bitmap */
#define UDF_ALLOC_METASEQUENTIAL 5 /* in chunks seq., nodes not seq */
#define UDF_ALLOC_RELAXEDSEQUENTIAL 6 /* only nodes not seq. */
/* readdir cookies */
#define UDF_DIRCOOKIE_DOT 1
/*
* UDF node describing a file/directory.
*
* BUGALERT claim node_mutex before reading/writing to prevent inconsistencies !
*/
struct udf_node {
struct genfs_node i_gnode; /* has to be first */
struct vnode *vnode; /* vnode associated */
struct udf_mount *ump;
kmutex_t node_mutex;
kcondvar_t node_lock; /* sleeping lock */
char const *lock_fname;
int lock_lineno;
/* one of `fe' or `efe' can be set, not both (UDF file entry dscr.) */
struct file_entry *fe;
struct extfile_entry *efe;
struct alloc_ext_entry *ext[UDF_MAX_ALLOC_EXTENTS];
int num_extensions;
/* location found and recording location & hints */
/* location found, recording location & hints */
struct long_ad loc; /* FID/hash loc. */
struct long_ad next_loc; /* strat 4096 loc */
struct long_ad write_loc; /* strat 4096 loc */
int needs_indirect; /* has missing indr. */
struct long_ad ext_loc[UDF_MAX_ALLOC_EXTENTS];
uint64_t last_diroffset; /* speeding up lookup*/
/* TODO support for allocation extents? */
/* device number from extended attributes = makedev(min,maj) */
dev_t rdev;
/* misc */
uint32_t i_flags; /* associated flags */
struct lockf *lockf; /* lock list */
uint32_t outstanding_bufs; /* file data */
uint32_t outstanding_nodedscr; /* node dscr */
/* possibly not needed */
long refcnt;
int dirty;
int hold;
/* references to associated nodes */
struct udf_node *extattr;
struct udf_node *streamdir;
struct udf_node *my_parent; /* if extended attr. */
LIST_ENTRY(udf_node) hashchain; /* all udf nodes */
STAILQ_ENTRY(udf_node) dirty_nodes; /* dirty udf nodes */
LIST_ENTRY(udf_node) hashchain; /* inside hash line */
LIST_ENTRY(udf_node) sortchain; /* sorted udf nodes */
};
/* misc. flags stored in i_flags (XXX needs cleaning up) */
#define IN_ACCESS 0x0001 /* Inode access time update request. */
#define IN_CHANGE 0x0002 /* Inode change time update request. */
#define IN_UPDATE 0x0004 /* Inode was written to; update mtime*/
#define IN_MODIFY 0x0008 /* Modification time update request. */
#define IN_MODIFIED 0x0010 /* node has been modified. */
#define IN_ACCESSED 0x0020 /* node has been accessed. */
#define IN_RENAME 0x0040 /* node is being renamed. XXX ?? */
#define IN_DELETED 0x0080 /* node is unlinked, no FID reference */
#define IN_LOCKED 0x0100 /* node is locked by condvar */
#define IN_SYNCED 0x0200 /* node is being used by sync */
#define IN_CALLBACK_ULK 0x0400 /* node will be unlocked by callback */
#define IN_FLAGBITS \
"\10\1IN_ACCESS\2IN_CHANGE\3IN_UPDATE\4IN_MODIFY\5IN_MODIFIED" \
"\6IN_ACCESSED\7IN_RENAME\10IN_DELETED\11IN_LOCKED\12IN_SYNCED" \
"\13IN_CALLBACK_ULK"
#endif /* !_FS_UDF_UDF_H_ */

2338
sys/fs/udf/udf_allocation.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
/* $NetBSD: udf_bswap.h,v 1.4 2006/03/05 16:55:44 christos Exp $ */
/* $NetBSD: udf_bswap.h,v 1.5 2008/05/14 16:49:48 reinoud Exp $ */
/*
* Copyright (c) 1998 Manuel Bouyer.

View File

@ -1,7 +1,9 @@
/* $NetBSD: udf_osta.c,v 1.5 2007/12/11 12:05:27 lukem Exp $ */
/* $NetBSD: udf_osta.c,v 1.6 2008/05/14 16:49:48 reinoud Exp $ */
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: udf_osta.c,v 1.5 2007/12/11 12:05:27 lukem Exp $");
#ifndef lint
__KERNEL_RCSID(0, "$NetBSD: udf_osta.c,v 1.6 2008/05/14 16:49:48 reinoud Exp $");
#endif /* not lint */
/*
* Various routines from the OSTA 2.01 specs. Copyrights are included with
@ -12,6 +14,9 @@ __KERNEL_RCSID(0, "$NetBSD: udf_osta.c,v 1.5 2007/12/11 12:05:27 lukem Exp $");
#include "udf_osta.h"
#ifndef _KERNEL
#include <ctype.h>
#endif
/*****************************************************************************/
/***********************************************************************
@ -199,6 +204,27 @@ udf_unicode_cksum(s, n)
return crc;
}
/*
* Calculates a 16-bit checksum of the Implementation Use
* Extended Attribute header or Application Use Extended Attribute
* header. The fields AttributeType through ImplementationIdentifier
* (or ApplicationIdentifier) inclusively represent the
* data covered by the checksum (48 bytes).
*
*/
uint16_t udf_ea_cksum(uint8_t *data) {
uint16_t checksum = 0;
int count;
for (count = 0; count < 48; count++) {
checksum += *data++;
}
return checksum;
}
#ifdef MAIN
unsigned char bytes[] = { 0x70, 0x6A, 0x77 };
@ -275,9 +301,11 @@ int UnicodeLength(unicode_t *string) {
}
static int isprint(unsigned char c) {
#ifdef _KERNEL
static int isprint(int c) {
return (c >= ' ') && (c != 127);
}
#endif
/***********************************************************************

View File

@ -1,4 +1,4 @@
/* $NetBSD: udf_osta.h,v 1.3 2006/03/05 16:55:44 christos Exp $ */
/* $NetBSD: udf_osta.h,v 1.4 2008/05/14 16:49:48 reinoud Exp $ */
/*
* Prototypes for the OSTA functions
@ -8,9 +8,12 @@
#ifndef _FS_UDF_OSTA_H_
#define _FS_UDF_OSTA_H_
#include <sys/types.h>
#ifndef _KERNEL
#include <stdbool.h>
#endif
#ifndef UNIX
#define UNIX
#endif
@ -33,6 +36,7 @@ int udf_UncompressUnicode(int, byte *, unicode_t *);
int udf_CompressUnicode(int, int, unicode_t *, byte *);
unsigned short udf_cksum(unsigned char *, int);
unsigned short udf_unicode_cksum(unsigned short *, int);
uint16_t udf_ea_cksum(uint8_t *data);
int UDFTransName(unicode_t *, unicode_t *, int);
int UnicodeLength(unicode_t *string);

658
sys/fs/udf/udf_readwrite.c Normal file
View File

@ -0,0 +1,658 @@
/* $NetBSD: udf_readwrite.c,v 1.1 2008/05/14 16:49:48 reinoud Exp $ */
/*
* Copyright (c) 2007, 2008 Reinoud Zandijk
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <sys/cdefs.h>
#ifndef lint
__KERNEL_RCSID(0, "$NetBSD: udf_readwrite.c,v 1.1 2008/05/14 16:49:48 reinoud Exp $");
#endif /* not lint */
#if defined(_KERNEL_OPT)
#include "opt_quota.h"
#include "opt_compat_netbsd.h"
#endif
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/sysctl.h>
#include <sys/namei.h>
#include <sys/proc.h>
#include <sys/kernel.h>
#include <sys/vnode.h>
#include <miscfs/genfs/genfs_node.h>
#include <sys/mount.h>
#include <sys/buf.h>
#include <sys/file.h>
#include <sys/device.h>
#include <sys/disklabel.h>
#include <sys/ioctl.h>
#include <sys/malloc.h>
#include <sys/dirent.h>
#include <sys/stat.h>
#include <sys/conf.h>
#include <sys/kauth.h>
#include <sys/kthread.h>
#include <dev/clock_subr.h>
#include <fs/udf/ecma167-udf.h>
#include <fs/udf/udf_mount.h>
#if defined(_KERNEL_OPT)
#include "opt_udf.h"
#endif
#include "udf.h"
#include "udf_subr.h"
#include "udf_bswap.h"
#define VTOI(vnode) ((struct udf_node *) vnode->v_data)
/* --------------------------------------------------------------------- */
void
udf_fixup_fid_block(uint8_t *blob, int lb_size,
int rfix_pos, int max_rfix_pos, uint32_t lb_num)
{
struct fileid_desc *fid;
uint8_t *fid_pos;
int fid_len, found;
/* needs to be word aligned */
KASSERT(rfix_pos % 4 == 0);
/* first resync with the FID stream !!! */
found = 0;
while (rfix_pos + sizeof(struct desc_tag) <= max_rfix_pos) {
fid_pos = blob + rfix_pos;
fid = (struct fileid_desc *) fid_pos;
if (udf_rw16(fid->tag.id) == TAGID_FID) {
if (udf_check_tag((union dscrptr *) fid) == 0)
found = 1;
}
if (found)
break;
/* try next location; can only be 4 bytes aligned */
rfix_pos += 4;
}
/* walk over the fids */
fid_pos = blob + rfix_pos;
while (rfix_pos + sizeof(struct desc_tag) <= max_rfix_pos) {
fid = (struct fileid_desc *) fid_pos;
if (udf_rw16(fid->tag.id) != TAGID_FID) {
/* end of FID stream; end of directory or currupted */
break;
}
/* update sector number and recalculate checkum */
fid->tag.tag_loc = udf_rw32(lb_num);
udf_validate_tag_sum((union dscrptr *) fid);
/* if the FID crosses the memory, we're done! */
if (rfix_pos + UDF_FID_SIZE >= max_rfix_pos)
break;
fid_len = udf_fidsize(fid);
fid_pos += fid_len;
rfix_pos += fid_len;
}
}
void
udf_fixup_internal_extattr(uint8_t *blob, uint32_t lb_num)
{
struct desc_tag *tag;
struct file_entry *fe;
struct extfile_entry *efe;
struct extattrhdr_desc *eahdr;
int l_ea, error;
/* get information from fe/efe */
tag = (struct desc_tag *) blob;
switch (udf_rw16(tag->id)) {
case TAGID_FENTRY :
fe = (struct file_entry *) blob;
l_ea = udf_rw32(fe->l_ea);
eahdr = (struct extattrhdr_desc *) fe->data;
break;
case TAGID_EXTFENTRY :
efe = (struct extfile_entry *) blob;
l_ea = udf_rw32(efe->l_ea);
eahdr = (struct extattrhdr_desc *) efe->data;
break;
case TAGID_INDIRECTENTRY :
case TAGID_ALLOCEXTENT :
case TAGID_EXTATTR_HDR :
return;
default:
panic("%s: passed bad tag\n", __FUNCTION__);
}
/* something recorded here? (why am i called?) */
if (l_ea == 0)
return;
/* check extended attribute tag */
/* TODO XXX what to do when we encounter an error here? */
error = udf_check_tag(eahdr);
if (error)
return; /* for now */
if (udf_rw16(eahdr->tag.id) != TAGID_EXTATTR_HDR)
return; /* for now */
error = udf_check_tag_payload(eahdr, sizeof(struct extattrhdr_desc));
if (error)
return; /* for now */
DPRINTF(EXTATTR, ("node fixup: found %d bytes of extended attributes\n",
l_ea));
/* fixup eahdr tag */
eahdr->tag.tag_loc = udf_rw32(lb_num);
udf_validate_tag_sum((union dscrptr *) eahdr);
}
void
udf_fixup_node_internals(struct udf_mount *ump, uint8_t *blob, int udf_c_type)
{
struct desc_tag *tag;
struct file_entry *fe;
struct extfile_entry *efe;
uint32_t lb_size, lb_num;
uint32_t rfid_pos, max_rfid_pos;
int icbflags, addr_type, has_fids, l_ea;
lb_size = udf_rw32(ump->logical_vol->lb_size);
/* if its not a node we're done */
if (udf_c_type != UDF_C_NODE)
return;
/* NOTE this could also be done in write_internal */
/* start of a descriptor */
has_fids = 0;
max_rfid_pos = rfid_pos = lb_num = 0; /* shut up gcc! */
tag = (struct desc_tag *) blob;
switch (udf_rw16(tag->id)) {
case TAGID_FENTRY :
fe = (struct file_entry *) tag;
l_ea = udf_rw32(fe->l_ea);
icbflags = udf_rw16(fe->icbtag.flags);
addr_type = (icbflags & UDF_ICB_TAG_FLAGS_ALLOC_MASK);
has_fids = (addr_type == UDF_ICB_INTERN_ALLOC);
rfid_pos = UDF_FENTRY_SIZE + l_ea;
max_rfid_pos = rfid_pos + udf_rw64(fe->inf_len);
lb_num = udf_rw32(fe->tag.tag_loc);
break;
case TAGID_EXTFENTRY :
efe = (struct extfile_entry *) tag;
l_ea = udf_rw32(efe->l_ea);
icbflags = udf_rw16(efe->icbtag.flags);
addr_type = (icbflags & UDF_ICB_TAG_FLAGS_ALLOC_MASK);
has_fids = (addr_type == UDF_ICB_INTERN_ALLOC);
rfid_pos = UDF_EXTFENTRY_SIZE + l_ea;
max_rfid_pos = rfid_pos + udf_rw64(efe->inf_len);
lb_num = udf_rw32(efe->tag.tag_loc);
break;
case TAGID_INDIRECTENTRY :
case TAGID_ALLOCEXTENT :
case TAGID_EXTATTR_HDR :
l_ea = 0;
has_fids = 0;
break;
default:
panic("%s: passed bad tag\n", __FUNCTION__);
break;
}
/* fixup internal extended attributes if present */
if (l_ea)
udf_fixup_internal_extattr(blob, lb_num);
if (has_fids) {
udf_fixup_fid_block(blob, lb_size, rfid_pos,
max_rfid_pos, lb_num);
}
udf_validate_tag_and_crc_sums(blob);
}
/* --------------------------------------------------------------------- */
/*
* Set of generic descriptor readers and writers and their helper functions.
* Descriptors inside `logical space' i.e. inside logically mapped partitions
* can never be longer than one logical sector.
*
* NOTE that these functions *can* be used by the sheduler backends to read
* node descriptors too.
*
* For reading, the size of allocated piece is returned in multiple of sector
* size due to udf_calc_udf_malloc_size().
*/
/* SYNC reading of n blocks from specified sector */
/* NOTE only used by udf_read_phys_dscr */
static int
udf_read_phys_sectors(struct udf_mount *ump, int what, void *blob,
uint32_t start, uint32_t sectors)
{
struct buf *buf, *nestbuf;
uint32_t buf_offset;
off_t lblkno, rblkno;
int sector_size = ump->discinfo.sector_size;
int blks = sector_size / DEV_BSIZE;
int piece;
int error;
DPRINTF(READ, ("udf_intbreadn() : sectors = %d, sector_size = %d\n",
sectors, sector_size));
buf = getiobuf(ump->devvp, true);
buf->b_flags = B_READ;
buf->b_cflags = BC_BUSY; /* needed? */
buf->b_iodone = NULL;
buf->b_data = blob;
buf->b_bcount = sectors * sector_size;
buf->b_resid = buf->b_bcount;
buf->b_bufsize = buf->b_bcount;
buf->b_private = NULL; /* not needed yet */
BIO_SETPRIO(buf, BPRIO_DEFAULT);
buf->b_lblkno = buf->b_blkno = buf->b_rawblkno = start * blks;
buf->b_proc = NULL;
error = 0;
buf_offset = 0;
rblkno = start;
lblkno = 0;
while ((sectors > 0) && (error == 0)) {
piece = MIN(MAXPHYS/sector_size, sectors);
DPRINTF(READ, ("read in %d + %d\n", (uint32_t) rblkno, piece));
nestbuf = getiobuf(NULL, true);
nestiobuf_setup(buf, nestbuf, buf_offset, piece * sector_size);
/* nestbuf is B_ASYNC */
/* identify this nestbuf */
nestbuf->b_lblkno = lblkno;
/* CD shedules on raw blkno */
nestbuf->b_blkno = rblkno * blks;
nestbuf->b_proc = NULL;
nestbuf->b_rawblkno = rblkno * blks;
nestbuf->b_udf_c_type = what;
udf_discstrat_queuebuf(ump, nestbuf);
lblkno += piece;
rblkno += piece;
buf_offset += piece * sector_size;
sectors -= piece;
}
error = biowait(buf);
putiobuf(buf);
return error;
}
/* synchronous generic descriptor read */
int
udf_read_phys_dscr(struct udf_mount *ump, uint32_t sector,
struct malloc_type *mtype, union dscrptr **dstp)
{
union dscrptr *dst, *new_dst;
uint8_t *pos;
int sectors, dscrlen;
int i, error, sector_size;
sector_size = ump->discinfo.sector_size;
*dstp = dst = NULL;
dscrlen = sector_size;
/* read initial piece */
dst = malloc(sector_size, mtype, M_WAITOK);
error = udf_read_phys_sectors(ump, UDF_C_DSCR, dst, sector, 1);
DPRINTFIF(DESCRIPTOR, error, ("read error (%d)\n", error));
if (!error) {
/* check if its a valid tag */
error = udf_check_tag(dst);
if (error) {
/* check if its an empty block */
pos = (uint8_t *) dst;
for (i = 0; i < sector_size; i++, pos++) {
if (*pos) break;
}
if (i == sector_size) {
/* return no error but with no dscrptr */
/* dispose first block */
free(dst, mtype);
return 0;
}
}
/* calculate descriptor size */
dscrlen = udf_tagsize(dst, sector_size);
}
DPRINTFIF(DESCRIPTOR, error, ("bad tag checksum\n"));
if (!error && (dscrlen > sector_size)) {
DPRINTF(DESCRIPTOR, ("multi block descriptor read\n"));
/*
* Read the rest of descriptor. Since it is only used at mount
* time its overdone to define and use a specific udf_intbreadn
* for this alone.
*/
new_dst = realloc(dst, dscrlen, mtype, M_WAITOK);
if (new_dst == NULL) {
free(dst, mtype);
return ENOMEM;
}
dst = new_dst;
sectors = (dscrlen + sector_size -1) / sector_size;
DPRINTF(DESCRIPTOR, ("dscrlen = %d (%d blk)\n", dscrlen, sectors));
pos = (uint8_t *) dst + sector_size;
error = udf_read_phys_sectors(ump, UDF_C_DSCR, pos,
sector + 1, sectors-1);
DPRINTFIF(DESCRIPTOR, error, ("read error on multi (%d)\n",
error));
}
if (!error) {
error = udf_check_tag_payload(dst, dscrlen);
DPRINTFIF(DESCRIPTOR, error, ("bad payload check sum\n"));
}
if (error && dst) {
free(dst, mtype);
dst = NULL;
}
*dstp = dst;
return error;
}
static void
udf_write_phys_buf(struct udf_mount *ump, int what, struct buf *buf)
{
struct buf *nestbuf;
uint32_t buf_offset;
off_t lblkno, rblkno;
int sector_size = ump->discinfo.sector_size;
int blks = sector_size / DEV_BSIZE;
uint32_t sectors;
int piece;
int error;
sectors = buf->b_bcount / sector_size;
DPRINTF(WRITE, ("udf_intbwriten() : sectors = %d, sector_size = %d\n",
sectors, sector_size));
/* don't forget to increase pending count for the bwrite itself */
/* panic("NO WRITING\n"); */
if (buf->b_vp) {
mutex_enter(&buf->b_vp->v_interlock);
buf->b_vp->v_numoutput++;
mutex_exit(&buf->b_vp->v_interlock);
}
error = 0;
buf_offset = 0;
rblkno = buf->b_blkno / blks;
lblkno = 0;
while ((sectors > 0) && (error == 0)) {
piece = MIN(MAXPHYS/sector_size, sectors);
DPRINTF(WRITE, ("write out %d + %d\n",
(uint32_t) rblkno, piece));
nestbuf = getiobuf(NULL, true);
nestiobuf_setup(buf, nestbuf, buf_offset, piece * sector_size);
/* nestbuf is B_ASYNC */
/* identify this nestbuf */
nestbuf->b_lblkno = lblkno;
/* CD shedules on raw blkno */
nestbuf->b_blkno = rblkno * blks;
nestbuf->b_proc = NULL;
nestbuf->b_rawblkno = rblkno * blks;
nestbuf->b_udf_c_type = what;
udf_discstrat_queuebuf(ump, nestbuf);
lblkno += piece;
rblkno += piece;
buf_offset += piece * sector_size;
sectors -= piece;
}
}
/* synchronous generic descriptor write */
int
udf_write_phys_dscr_sync(struct udf_mount *ump, struct udf_node *udf_node, int what,
union dscrptr *dscr, uint32_t sector, uint32_t logsector)
{
struct vnode *vp;
struct buf *buf;
int sector_size = ump->discinfo.sector_size;
int blks = sector_size / DEV_BSIZE;
int dscrlen;
int error;
/* set sector number in the descriptor and validate */
dscr->tag.tag_loc = udf_rw32(logsector);
udf_validate_tag_and_crc_sums(dscr);
/* calculate descriptor size */
dscrlen = udf_tagsize(dscr, sector_size);
/* get transfer buffer */
vp = udf_node ? udf_node->vnode : ump->devvp;
buf = getiobuf(vp, true);
buf->b_flags = B_WRITE;
buf->b_cflags = BC_BUSY; /* needed? */
buf->b_iodone = NULL;
buf->b_data = (void *) dscr;
buf->b_bcount = dscrlen;
buf->b_resid = buf->b_bcount;
buf->b_bufsize = buf->b_bcount;
buf->b_private = NULL; /* not needed yet */
BIO_SETPRIO(buf, BPRIO_DEFAULT);
buf->b_lblkno = buf->b_blkno = buf->b_rawblkno = sector * blks;
buf->b_proc = NULL;
/* do the write, wait and return error */
udf_write_phys_buf(ump, what, buf);
error = biowait(buf);
putiobuf(buf);
return error;
}
/* asynchronous generic descriptor write */
int
udf_write_phys_dscr_async(struct udf_mount *ump, struct udf_node *udf_node,
int what, union dscrptr *dscr,
uint32_t sector, uint32_t logsector,
void (*dscrwr_callback)(struct buf *))
{
struct vnode *vp;
struct buf *buf;
int dscrlen;
int sector_size = ump->discinfo.sector_size;
int blks = sector_size / DEV_BSIZE;
KASSERT(dscrwr_callback);
DPRINTF(NODE, ("udf_write_phys_dscr_async() called\n"));
/* set sector number in the descriptor and validate */
dscr->tag.tag_loc = udf_rw32(logsector);
udf_validate_tag_and_crc_sums(dscr);
/* calculate descriptor size */
dscrlen = udf_tagsize(dscr, sector_size);
/* get transfer buffer */
vp = udf_node ? udf_node->vnode : ump->devvp;
buf = getiobuf(vp, true);
buf->b_flags = B_WRITE; // | B_ASYNC;
buf->b_cflags = BC_BUSY;
buf->b_iodone = dscrwr_callback;
buf->b_data = dscr;
buf->b_bcount = dscrlen;
buf->b_resid = buf->b_bcount;
buf->b_bufsize = buf->b_bcount;
buf->b_private = NULL; /* not needed yet */
BIO_SETPRIO(buf, BPRIO_DEFAULT);
buf->b_lblkno = buf->b_blkno = buf->b_rawblkno = sector * blks;
buf->b_proc = NULL;
/* do the write and return no error */
udf_write_phys_buf(ump, what, buf);
return 0;
}
/* --------------------------------------------------------------------- */
/* disc strategy dispatchers */
int
udf_create_logvol_dscr(struct udf_mount *ump, struct udf_node *udf_node, struct long_ad *icb,
union dscrptr **dscrptr)
{
struct udf_strategy *strategy = ump->strategy;
struct udf_strat_args args;
int error;
args.ump = ump;
args.udf_node = udf_node;
args.icb = icb;
args.dscr = NULL;
error = (strategy->create_logvol_dscr)(&args);
*dscrptr = args.dscr;
return error;
}
void
udf_free_logvol_dscr(struct udf_mount *ump, struct long_ad *icb,
void *dscr)
{
struct udf_strategy *strategy = ump->strategy;
struct udf_strat_args args;
args.ump = ump;
args.icb = icb;
args.dscr = dscr;
(strategy->free_logvol_dscr)(&args);
}
int
udf_read_logvol_dscr(struct udf_mount *ump, struct long_ad *icb,
union dscrptr **dscrptr)
{
struct udf_strategy *strategy = ump->strategy;
struct udf_strat_args args;
int error;
args.ump = ump;
args.icb = icb;
args.dscr = NULL;
error = (strategy->read_logvol_dscr)(&args);
*dscrptr = args.dscr;
return error;
}
int
udf_write_logvol_dscr(struct udf_node *udf_node, union dscrptr *dscr,
struct long_ad *icb, int waitfor)
{
struct udf_strategy *strategy = udf_node->ump->strategy;
struct udf_strat_args args;
int error;
args.ump = udf_node->ump;
args.udf_node = udf_node;
args.icb = icb;
args.dscr = dscr;
args.waitfor = waitfor;
error = (strategy->write_logvol_dscr)(&args);
return error;
}
void
udf_discstrat_queuebuf(struct udf_mount *ump, struct buf *nestbuf)
{
struct udf_strategy *strategy = ump->strategy;
struct udf_strat_args args;
args.ump = ump;
args.nestbuf = nestbuf;
(strategy->queuebuf)(&args);
}
void
udf_discstrat_init(struct udf_mount *ump)
{
struct udf_strategy *strategy = ump->strategy;
struct udf_strat_args args;
args.ump = ump;
(strategy->discstrat_init)(&args);
}
void udf_discstrat_finish(struct udf_mount *ump)
{
struct udf_strategy *strategy = ump->strategy;
struct udf_strat_args args;
args.ump = ump;
(strategy->discstrat_finish)(&args);
}
/* --------------------------------------------------------------------- */

View File

@ -0,0 +1,150 @@
/* $NetBSD: udf_strat_bootstrap.c,v 1.1 2008/05/14 16:49:48 reinoud Exp $ */
/*
* Copyright (c) 2006, 2008 Reinoud Zandijk
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <sys/cdefs.h>
#ifndef lint
__KERNEL_RCSID(0, "$NetBSD: udf_strat_bootstrap.c,v 1.1 2008/05/14 16:49:48 reinoud Exp $");
#endif /* not lint */
#if defined(_KERNEL_OPT)
#include "opt_quota.h"
#include "opt_compat_netbsd.h"
#endif
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/sysctl.h>
#include <sys/namei.h>
#include <sys/proc.h>
#include <sys/kernel.h>
#include <sys/vnode.h>
#include <miscfs/genfs/genfs_node.h>
#include <sys/mount.h>
#include <sys/buf.h>
#include <sys/file.h>
#include <sys/device.h>
#include <sys/disklabel.h>
#include <sys/ioctl.h>
#include <sys/malloc.h>
#include <sys/dirent.h>
#include <sys/stat.h>
#include <sys/conf.h>
#include <sys/kauth.h>
#include <sys/kthread.h>
#include <dev/clock_subr.h>
#include <fs/udf/ecma167-udf.h>
#include <fs/udf/udf_mount.h>
#if defined(_KERNEL_OPT)
#include "opt_udf.h"
#endif
#include "udf.h"
#include "udf_subr.h"
#include "udf_bswap.h"
#define VTOI(vnode) ((struct udf_node *) vnode->v_data)
#define PRIV(ump) ((struct strat_private *) ump->strategy_private)
/* --------------------------------------------------------------------- */
static int
udf_create_logvol_dscr_bootstrap(struct udf_strat_args *args)
{
panic("udf_create_logvol_dscr_bootstrap: not possible\n");
return 0;
}
static void
udf_free_logvol_dscr_bootstrap(struct udf_strat_args *args)
{
panic("udf_free_logvol_dscr_bootstrap: no node descriptor reading\n");
}
static int
udf_read_logvol_dscr_bootstrap(struct udf_strat_args *args)
{
panic("udf_read_logvol_dscr_bootstrap: no node descriptor reading\n");
return 0;
}
static int
udf_write_logvol_dscr_bootstrap(struct udf_strat_args *args)
{
panic("udf_write_logvol_dscr_bootstrap: no writing\n");
}
/* --------------------------------------------------------------------- */
static void
udf_queuebuf_bootstrap(struct udf_strat_args *args)
{
struct udf_mount *ump = args->ump;
struct buf *buf = args->nestbuf;
KASSERT(ump);
KASSERT(buf);
KASSERT(buf->b_iodone == nestiobuf_iodone);
KASSERT(buf->b_flags & B_READ);
VOP_STRATEGY(ump->devvp, buf);
}
static void
udf_discstrat_init_bootstrap(struct udf_strat_args *args)
{
/* empty */
}
static void
udf_discstrat_finish_bootstrap(struct udf_strat_args *args)
{
/* empty */
}
/* --------------------------------------------------------------------- */
struct udf_strategy udf_strat_bootstrap =
{
udf_create_logvol_dscr_bootstrap,
udf_free_logvol_dscr_bootstrap,
udf_read_logvol_dscr_bootstrap,
udf_write_logvol_dscr_bootstrap,
udf_queuebuf_bootstrap,
udf_discstrat_init_bootstrap,
udf_discstrat_finish_bootstrap
};

View File

@ -0,0 +1,450 @@
/* $NetBSD: udf_strat_direct.c,v 1.1 2008/05/14 16:49:48 reinoud Exp $ */
/*
* Copyright (c) 2006, 2008 Reinoud Zandijk
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <sys/cdefs.h>
#ifndef lint
__KERNEL_RCSID(0, "$NetBSD: udf_strat_direct.c,v 1.1 2008/05/14 16:49:48 reinoud Exp $");
#endif /* not lint */
#if defined(_KERNEL_OPT)
#include "opt_quota.h"
#include "opt_compat_netbsd.h"
#endif
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/sysctl.h>
#include <sys/namei.h>
#include <sys/proc.h>
#include <sys/kernel.h>
#include <sys/vnode.h>
#include <miscfs/genfs/genfs_node.h>
#include <sys/mount.h>
#include <sys/buf.h>
#include <sys/file.h>
#include <sys/device.h>
#include <sys/disklabel.h>
#include <sys/ioctl.h>
#include <sys/malloc.h>
#include <sys/dirent.h>
#include <sys/stat.h>
#include <sys/conf.h>
#include <sys/kauth.h>
#include <sys/kthread.h>
#include <dev/clock_subr.h>
#include <fs/udf/ecma167-udf.h>
#include <fs/udf/udf_mount.h>
#if defined(_KERNEL_OPT)
#include "opt_udf.h"
#endif
#include "udf.h"
#include "udf_subr.h"
#include "udf_bswap.h"
#define VTOI(vnode) ((struct udf_node *) vnode->v_data)
#define PRIV(ump) ((struct strat_private *) ump->strategy_private)
/* --------------------------------------------------------------------- */
/* BUFQ's */
#define UDF_SHED_MAX 3
#define UDF_SHED_READING 0
#define UDF_SHED_WRITING 1
#define UDF_SHED_SEQWRITING 2
struct strat_private {
struct pool desc_pool; /* node descriptors */
};
/* --------------------------------------------------------------------- */
static void
udf_wr_nodedscr_callback(struct buf *buf)
{
struct udf_node *udf_node;
KASSERT(buf);
KASSERT(buf->b_data);
/* called when write action is done */
DPRINTF(WRITE, ("udf_wr_nodedscr_callback(): node written out\n"));
udf_node = VTOI(buf->b_vp);
if (udf_node == NULL) {
putiobuf(buf);
printf("udf_wr_node_callback: NULL node?\n");
return;
}
/* XXX noone is waiting on this outstanding_nodedscr */
udf_node->outstanding_nodedscr--;
if (udf_node->outstanding_nodedscr == 0)
wakeup(&udf_node->outstanding_nodedscr);
/* XXX right flags to mark dirty again on error? */
if (buf->b_error) {
/* write error on `defect free' media??? how to solve? */
/* XXX lookup UDF standard for unallocatable space */
udf_node->i_flags |= IN_MODIFIED | IN_ACCESSED;
}
/* first unlock the node */
KASSERT(udf_node->i_flags & IN_CALLBACK_ULK);
UDF_UNLOCK_NODE(udf_node, IN_CALLBACK_ULK);
/* unreference the vnode so it can be recycled */
holdrele(udf_node->vnode);
putiobuf(buf);
}
/* --------------------------------------------------------------------- */
static int
udf_getblank_nodedscr_direct(struct udf_strat_args *args)
{
union dscrptr **dscrptr = &args->dscr;
struct udf_mount *ump = args->ump;
struct strat_private *priv = PRIV(ump);
uint32_t lb_size;
lb_size = udf_rw32(ump->logical_vol->lb_size);
*dscrptr = pool_get(&priv->desc_pool, PR_WAITOK);
memset(*dscrptr, 0, lb_size);
return 0;
}
static void
udf_free_nodedscr_direct(struct udf_strat_args *args)
{
union dscrptr *dscr = args->dscr;
struct udf_mount *ump = args->ump;
struct strat_private *priv = PRIV(ump);
pool_put(&priv->desc_pool, dscr);
}
static int
udf_read_nodedscr_direct(struct udf_strat_args *args)
{
union dscrptr **dscrptr = &args->dscr;
union dscrptr *tmpdscr;
struct udf_mount *ump = args->ump;
struct long_ad *icb = args->icb;
struct strat_private *priv = PRIV(ump);
uint32_t lb_size;
uint32_t sector, dummy;
int error;
lb_size = udf_rw32(ump->logical_vol->lb_size);
error = udf_translate_vtop(ump, icb, &sector, &dummy);
if (error)
return error;
/* try to read in fe/efe */
error = udf_read_phys_dscr(ump, sector, M_UDFTEMP, &tmpdscr);
if (error)
return error;
*dscrptr = pool_get(&priv->desc_pool, PR_WAITOK);
memcpy(*dscrptr, tmpdscr, lb_size);
free(tmpdscr, M_UDFTEMP);
return 0;
}
static int
udf_write_nodedscr_direct(struct udf_strat_args *args)
{
struct udf_mount *ump = args->ump;
struct udf_node *udf_node = args->udf_node;
union dscrptr *dscr = args->dscr;
struct long_ad *icb = args->icb;
int waitfor = args->waitfor;
uint32_t logsector, sector, dummy;
int error, vpart;
/*
* we have to decide if we write it out sequential or at its fixed
* position by examining the partition its (to be) written on.
*/
vpart = udf_rw16(udf_node->loc.loc.part_num);
logsector = udf_rw32(icb->loc.lb_num);
KASSERT(ump->vtop_tp[vpart] != UDF_VTOP_TYPE_VIRT);
sector = 0;
error = udf_translate_vtop(ump, icb, &sector, &dummy);
if (error)
return error;
UDF_LOCK_NODE(udf_node, IN_CALLBACK_ULK);
if (waitfor) {
DPRINTF(WRITE, ("udf_write_nodedscr: sync write\n"));
error = udf_write_phys_dscr_sync(ump, udf_node, UDF_C_NODE,
dscr, sector, logsector);
UDF_UNLOCK_NODE(udf_node, IN_CALLBACK_ULK);
} else {
DPRINTF(WRITE, ("udf_write_nodedscr: no wait, async write\n"));
/* add reference to the vnode to prevent recycling */
vhold(udf_node->vnode);
udf_node->outstanding_nodedscr++;
error = udf_write_phys_dscr_async(ump, udf_node, UDF_C_NODE,
dscr, sector, logsector, udf_wr_nodedscr_callback);
/* will be UNLOCKED in call back */
}
return error;
}
/* --------------------------------------------------------------------- */
static void
udf_queue_buf_direct(struct udf_strat_args *args)
{
struct udf_mount *ump = args->ump;
struct buf *buf = args->nestbuf;
struct buf *nestbuf;
struct long_ad *node_ad_cpy;
uint64_t *lmapping, *pmapping, *lmappos, blknr, run_start;
uint32_t our_sectornr, sectornr;
uint32_t lb_size, buf_offset, rbuflen, bpos;
uint8_t *fidblk;
off_t rblk;
int sector_size = ump->discinfo.sector_size;
int blks = sector_size / DEV_BSIZE;
int len, buf_len, sector, sectors, run_length;
int what, class, queue;
KASSERT(ump);
KASSERT(buf);
KASSERT(buf->b_iodone == nestiobuf_iodone);
what = buf->b_udf_c_type;
queue = UDF_SHED_READING;
if ((buf->b_flags & B_READ) == 0) {
/* writing */
queue = UDF_SHED_SEQWRITING;
if (what == UDF_C_DSCR)
queue = UDF_SHED_WRITING;
if (what == UDF_C_NODE)
queue = UDF_SHED_WRITING;
}
/* use disc sheduler */
class = ump->discinfo.mmc_class;
KASSERT((class == MMC_CLASS_UNKN) || (class == MMC_CLASS_DISC) ||
(ump->discinfo.mmc_cur & MMC_CAP_HW_DEFECTFREE));
if (queue == UDF_SHED_READING) {
DPRINTF(SHEDULE, ("\nudf_issue_buf READ %p : sector %d type %d,"
"b_resid %d, b_bcount %d, b_bufsize %d\n",
buf, (uint32_t) buf->b_blkno / blks, buf->b_udf_c_type,
buf->b_resid, buf->b_bcount, buf->b_bufsize));
VOP_STRATEGY(ump->devvp, buf);
return;
}
/* (sectorsize == lb_size) for UDF */
lb_size = udf_rw32(ump->logical_vol->lb_size);
blknr = buf->b_blkno;
our_sectornr = blknr / blks;
if (queue == UDF_SHED_WRITING) {
DPRINTF(SHEDULE, ("\nudf_issue_buf WRITE %p : sector %d "
"type %d, b_resid %d, b_bcount %d, b_bufsize %d\n",
buf, (uint32_t) buf->b_blkno / blks, buf->b_udf_c_type,
buf->b_resid, buf->b_bcount, buf->b_bufsize));
/* if we have FIDs fixup using buffer's sector number(s) */
if (buf->b_udf_c_type == UDF_C_FIDS) {
panic("UDF_C_FIDS in SHED_WRITING!\n");
buf_len = buf->b_bcount;
sectornr = our_sectornr;
bpos = 0;
while (buf_len) {
len = MIN(buf_len, sector_size);
fidblk = (uint8_t *) buf->b_data + bpos;
udf_fixup_fid_block(fidblk, sector_size,
0, len, sectornr);
sectornr++;
bpos += len;
buf_len -= len;
}
}
udf_fixup_node_internals(ump, buf->b_data, buf->b_udf_c_type);
VOP_STRATEGY(ump->devvp, buf);
return;
}
/* UDF_SHED_SEQWRITING */
KASSERT(queue == UDF_SHED_SEQWRITING);
DPRINTF(SHEDULE, ("\nudf_issue_buf SEQWRITE %p : sector XXXX "
"type %d, b_resid %d, b_bcount %d, b_bufsize %d\n",
buf, buf->b_udf_c_type, buf->b_resid, buf->b_bcount,
buf->b_bufsize));
/*
* Buffers should not have been allocated to disc addresses yet on
* this queue. Note that a buffer can get multiple extents allocated.
*
* lmapping contains lb_num relative to base partition.
* pmapping contains lb_num as used for disc adressing.
*/
lmapping = ump->la_lmapping;
pmapping = ump->la_pmapping;
node_ad_cpy = ump->la_node_ad_cpy;
/* write physical blocknr in buf and get its mappings */
udf_late_allocate_buf(ump, buf, lmapping, pmapping, node_ad_cpy);
/* if we have FIDs, fixup using the new allocation table */
if (buf->b_udf_c_type == UDF_C_FIDS) {
buf_len = buf->b_bcount;
bpos = 0;
lmappos = lmapping;
while (buf_len) {
sectornr = *lmappos++;
len = MIN(buf_len, sector_size);
fidblk = (uint8_t *) buf->b_data + bpos;
udf_fixup_fid_block(fidblk, sector_size,
0, len, sectornr);
bpos += len;
buf_len -= len;
}
}
udf_fixup_node_internals(ump, buf->b_data, buf->b_udf_c_type);
/* speed up : try to conglomerate as many writes in one go */
sectors = (buf->b_bcount + sector_size -1) / sector_size;
for (sector = 0; sector < sectors; sector++) {
buf_offset = sector * sector_size;
DPRINTF(WRITE, ("\tprocessing rel sector %d\n", sector));
DPRINTF(WRITE, ("\tissue write sector %"PRIu64"\n",
pmapping[sector]));
run_start = pmapping[sector];
run_length = 1;
while (sector < sectors-1) {
if (pmapping[sector+1] != pmapping[sector]+1)
break;
run_length++;
sector++;
}
/* nest an iobuf for the extent */
rbuflen = run_length * sector_size;
rblk = run_start * (sector_size/DEV_BSIZE);
nestbuf = getiobuf(NULL, true);
nestiobuf_setup(buf, nestbuf, buf_offset, rbuflen);
/* nestbuf is B_ASYNC */
/* identify this nestbuf */
nestbuf->b_lblkno = sector;
assert(nestbuf->b_vp == buf->b_vp);
/* CD shedules on raw blkno */
nestbuf->b_blkno = rblk;
nestbuf->b_proc = NULL;
nestbuf->b_rawblkno = rblk;
nestbuf->b_udf_c_type = UDF_C_PROCESSED;
VOP_STRATEGY(ump->devvp, nestbuf);
}
}
static void
udf_discstrat_init_direct(struct udf_strat_args *args)
{
struct udf_mount *ump = args->ump;
struct strat_private *priv = PRIV(ump);
uint32_t lb_size;
KASSERT(priv == NULL);
ump->strategy_private = malloc(sizeof(struct strat_private),
M_UDFTEMP, M_WAITOK);
priv = ump->strategy_private;
memset(priv, 0 , sizeof(struct strat_private));
/*
* Initialise pool for descriptors associated with nodes. This is done
* in lb_size units though currently lb_size is dictated to be
* sector_size.
*/
memset(&priv->desc_pool, 0, sizeof(struct pool));
lb_size = udf_rw32(ump->logical_vol->lb_size);
pool_init(&priv->desc_pool, lb_size, 0, 0, 0, "udf_desc_pool", NULL,
IPL_NONE);
}
static void
udf_discstrat_finish_direct(struct udf_strat_args *args)
{
struct udf_mount *ump = args->ump;
struct strat_private *priv = PRIV(ump);
/* destroy our pool */
pool_destroy(&priv->desc_pool);
/* free our private space */
free(ump->strategy_private, M_UDFTEMP);
ump->strategy_private = NULL;
}
/* --------------------------------------------------------------------- */
struct udf_strategy udf_strat_direct =
{
udf_getblank_nodedscr_direct,
udf_free_nodedscr_direct,
udf_read_nodedscr_direct,
udf_write_nodedscr_direct,
udf_queue_buf_direct,
udf_discstrat_init_direct,
udf_discstrat_finish_direct
};

1401
sys/fs/udf/udf_strat_rmw.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,696 @@
/* $NetBSD: udf_strat_sequential.c,v 1.1 2008/05/14 16:49:48 reinoud Exp $ */
/*
* Copyright (c) 2006, 2008 Reinoud Zandijk
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <sys/cdefs.h>
#ifndef lint
__KERNEL_RCSID(0, "$NetBSD: udf_strat_sequential.c,v 1.1 2008/05/14 16:49:48 reinoud Exp $");
#endif /* not lint */
#if defined(_KERNEL_OPT)
#include "opt_quota.h"
#include "opt_compat_netbsd.h"
#endif
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/sysctl.h>
#include <sys/namei.h>
#include <sys/proc.h>
#include <sys/kernel.h>
#include <sys/vnode.h>
#include <miscfs/genfs/genfs_node.h>
#include <sys/mount.h>
#include <sys/buf.h>
#include <sys/file.h>
#include <sys/device.h>
#include <sys/disklabel.h>
#include <sys/ioctl.h>
#include <sys/malloc.h>
#include <sys/dirent.h>
#include <sys/stat.h>
#include <sys/conf.h>
#include <sys/kauth.h>
#include <sys/kthread.h>
#include <dev/clock_subr.h>
#include <fs/udf/ecma167-udf.h>
#include <fs/udf/udf_mount.h>
#if defined(_KERNEL_OPT)
#include "opt_udf.h"
#endif
#include "udf.h"
#include "udf_subr.h"
#include "udf_bswap.h"
#define VTOI(vnode) ((struct udf_node *) vnode->v_data)
#define PRIV(ump) ((struct strat_private *) ump->strategy_private)
/* --------------------------------------------------------------------- */
/* BUFQ's */
#define UDF_SHED_MAX 3
#define UDF_SHED_READING 0
#define UDF_SHED_WRITING 1
#define UDF_SHED_SEQWRITING 2
struct strat_private {
struct pool desc_pool; /* node descriptors */
lwp_t *queue_lwp;
kcondvar_t discstrat_cv; /* to wait on */
kmutex_t discstrat_mutex; /* disc strategy */
int run_thread; /* thread control */
int cur_queue;
struct disk_strategy old_strategy_setting;
struct bufq_state *queues[UDF_SHED_MAX];
struct timespec last_queued[UDF_SHED_MAX];
};
/* --------------------------------------------------------------------- */
static void
udf_wr_nodedscr_callback(struct buf *buf)
{
struct udf_node *udf_node;
KASSERT(buf);
KASSERT(buf->b_data);
/* called when write action is done */
DPRINTF(WRITE, ("udf_wr_nodedscr_callback(): node written out\n"));
udf_node = VTOI(buf->b_vp);
if (udf_node == NULL) {
putiobuf(buf);
printf("udf_wr_node_callback: NULL node?\n");
return;
}
/* XXX noone is waiting on this outstanding_nodedscr */
udf_node->outstanding_nodedscr--;
if (udf_node->outstanding_nodedscr == 0)
wakeup(&udf_node->outstanding_nodedscr);
/* XXX right flags to mark dirty again on error? */
if (buf->b_error) {
udf_node->i_flags |= IN_MODIFIED | IN_ACCESSED;
/* XXX TODO reshedule on error */
}
/* first unlock the node */
KASSERT(udf_node->i_flags & IN_CALLBACK_ULK);
UDF_UNLOCK_NODE(udf_node, IN_CALLBACK_ULK);
/* unreference the vnode so it can be recycled */
holdrele(udf_node->vnode);
putiobuf(buf);
}
/* --------------------------------------------------------------------- */
static int
udf_create_logvol_dscr_seq(struct udf_strat_args *args)
{
union dscrptr **dscrptr = &args->dscr;
struct udf_mount *ump = args->ump;
struct strat_private *priv = PRIV(ump);
uint32_t lb_size;
lb_size = udf_rw32(ump->logical_vol->lb_size);
*dscrptr = pool_get(&priv->desc_pool, PR_WAITOK);
memset(*dscrptr, 0, lb_size);
return 0;
}
static void
udf_free_logvol_dscr_seq(struct udf_strat_args *args)
{
union dscrptr *dscr = args->dscr;
struct udf_mount *ump = args->ump;
struct strat_private *priv = PRIV(ump);
pool_put(&priv->desc_pool, dscr);
}
static int
udf_read_logvol_dscr_seq(struct udf_strat_args *args)
{
union dscrptr **dscrptr = &args->dscr;
union dscrptr *tmpdscr;
struct udf_mount *ump = args->ump;
struct long_ad *icb = args->icb;
struct strat_private *priv = PRIV(ump);
uint32_t lb_size;
uint32_t sector, dummy;
int error;
lb_size = udf_rw32(ump->logical_vol->lb_size);
error = udf_translate_vtop(ump, icb, &sector, &dummy);
if (error)
return error;
/* try to read in fe/efe */
error = udf_read_phys_dscr(ump, sector, M_UDFTEMP, &tmpdscr);
if (error)
return error;
*dscrptr = pool_get(&priv->desc_pool, PR_WAITOK);
memcpy(*dscrptr, tmpdscr, lb_size);
free(tmpdscr, M_UDFTEMP);
return 0;
}
static int
udf_write_logvol_dscr_seq(struct udf_strat_args *args)
{
union dscrptr *dscr = args->dscr;
struct udf_mount *ump = args->ump;
struct udf_node *udf_node = args->udf_node;
struct long_ad *icb = args->icb;
int waitfor = args->waitfor;
uint32_t logsectornr, sectornr, dummy;
int error, vpart;
/*
* we have to decide if we write it out sequential or at its fixed
* position by examining the partition its (to be) written on.
*/
vpart = udf_rw16(udf_node->loc.loc.part_num);
logsectornr = udf_rw32(icb->loc.lb_num);
sectornr = 0;
if (ump->vtop_tp[vpart] != UDF_VTOP_TYPE_VIRT) {
error = udf_translate_vtop(ump, icb, &sectornr, &dummy);
if (error)
return error;
}
UDF_LOCK_NODE(udf_node, IN_CALLBACK_ULK);
if (waitfor) {
DPRINTF(WRITE, ("udf_write_logvol_dscr: sync write\n"));
error = udf_write_phys_dscr_sync(ump, udf_node, UDF_C_NODE,
dscr, sectornr, logsectornr);
UDF_UNLOCK_NODE(udf_node, IN_CALLBACK_ULK);
} else {
DPRINTF(WRITE, ("udf_write_logvol_dscr: no wait, async write\n"));
/* add reference to the vnode to prevent recycling */
vhold(udf_node->vnode);
udf_node->outstanding_nodedscr++;
error = udf_write_phys_dscr_async(ump, udf_node, UDF_C_NODE,
dscr, sectornr, logsectornr, udf_wr_nodedscr_callback);
/* will be UNLOCKED in call back */
}
return error;
}
/* --------------------------------------------------------------------- */
/*
* Main file-system specific sheduler. Due to the nature of optical media
* sheduling can't be performed in the traditional way. Most OS
* implementations i've seen thus read or write a file atomically giving all
* kinds of side effects.
*
* This implementation uses a kernel thread to shedule the queued requests in
* such a way that is semi-optimal for optical media; this means aproximately
* (R*|(Wr*|Ws*))* since switching between reading and writing is expensive in
* time.
*/
static void
udf_queuebuf_seq(struct udf_strat_args *args)
{
struct udf_mount *ump = args->ump;
struct buf *nestbuf = args->nestbuf;
struct strat_private *priv = PRIV(ump);
int queue;
int what;
KASSERT(ump);
KASSERT(nestbuf);
KASSERT(nestbuf->b_iodone == nestiobuf_iodone);
what = nestbuf->b_udf_c_type;
queue = UDF_SHED_READING;
if ((nestbuf->b_flags & B_READ) == 0) {
/* writing */
queue = UDF_SHED_SEQWRITING;
if (what == UDF_C_DSCR)
queue = UDF_SHED_WRITING;
if (what == UDF_C_NODE) {
if (ump->meta_alloc != UDF_ALLOC_VAT)
queue = UDF_SHED_WRITING;
}
#if 0
if (queue == UDF_SHED_SEQWRITING) {
/* TODO do add sector to uncommitted space */
}
#endif
}
/* use our own sheduler lists for more complex sheduling */
mutex_enter(&priv->discstrat_mutex);
BUFQ_PUT(priv->queues[queue], nestbuf);
vfs_timestamp(&priv->last_queued[queue]);
mutex_exit(&priv->discstrat_mutex);
/* signal our thread that there might be something to do */
cv_signal(&priv->discstrat_cv);
}
/* --------------------------------------------------------------------- */
/* TODO convert to lb_size */
static void
udf_VAT_mapping_update(struct udf_mount *ump, struct buf *buf)
{
union dscrptr *fdscr = (union dscrptr *) buf->b_data;
struct vnode *vp = buf->b_vp;
struct udf_node *udf_node = VTOI(vp);
struct part_desc *pdesc;
uint32_t lb_size, blks;
uint32_t lb_num, lb_map;
uint32_t udf_rw32_lbmap;
int c_type = buf->b_udf_c_type;
int error;
/* only interested when we're using a VAT */
if (ump->meta_alloc != UDF_ALLOC_VAT)
return;
KASSERT(ump->vat_node);
/* only nodes are recorded in the VAT */
/* NOTE: and the fileset descriptor (FIXME ?) */
if (c_type != UDF_C_NODE)
return;
/* we now have an UDF FE/EFE node on media with VAT (or VAT itself) */
lb_size = udf_rw32(ump->logical_vol->lb_size);
blks = lb_size / DEV_BSIZE;
/* calculate offset from base partition */
pdesc = ump->partitions[ump->vtop[ump->metadata_part]];
lb_map = buf->b_blkno / blks;
lb_map -= udf_rw32(pdesc->start_loc);
udf_rw32_lbmap = udf_rw32(lb_map);
/* if we're the VAT itself, only update our assigned sector number */
if (udf_node == ump->vat_node) {
fdscr->tag.tag_loc = udf_rw32_lbmap;
udf_validate_tag_sum(fdscr);
DPRINTF(TRANSLATE, ("VAT assigned to sector %u\n",
udf_rw32(udf_rw32_lbmap)));
/* no use mapping the VAT node in the VAT */
return;
}
/* check for tag location is false for allocation extents */
KASSERT(fdscr->tag.tag_loc == udf_node->write_loc.loc.lb_num);
/* record new position in VAT file */
lb_num = udf_rw32(udf_node->write_loc.loc.lb_num);
DPRINTF(TRANSLATE, ("VAT entry change (log %u -> phys %u)\n",
lb_num, lb_map));
/* VAT should be the longer than this write, can't go wrong */
KASSERT(lb_num <= ump->vat_entries);
mutex_enter(&ump->allocate_mutex);
error = udf_vat_write(ump->vat_node,
(uint8_t *) &udf_rw32_lbmap, 4,
ump->vat_offset + lb_num * 4);
mutex_exit(&ump->allocate_mutex);
if (error)
panic( "udf_VAT_mapping_update: HELP! i couldn't "
"write in the VAT file ?\n");
}
static void
udf_issue_buf(struct udf_mount *ump, int queue, struct buf *buf)
{
struct long_ad *node_ad_cpy;
uint64_t *lmapping, *pmapping, *lmappos, blknr;
uint32_t our_sectornr, sectornr, bpos;
uint8_t *fidblk;
int sector_size = ump->discinfo.sector_size;
int blks = sector_size / DEV_BSIZE;
int len, buf_len;
/* if reading, just pass to the device's STRATEGY */
if (queue == UDF_SHED_READING) {
DPRINTF(SHEDULE, ("\nudf_issue_buf READ %p : sector %d type %d,"
"b_resid %d, b_bcount %d, b_bufsize %d\n",
buf, (uint32_t) buf->b_blkno / blks, buf->b_udf_c_type,
buf->b_resid, buf->b_bcount, buf->b_bufsize));
VOP_STRATEGY(ump->devvp, buf);
return;
}
blknr = buf->b_blkno;
our_sectornr = blknr / blks;
if (queue == UDF_SHED_WRITING) {
DPRINTF(SHEDULE, ("\nudf_issue_buf WRITE %p : sector %d "
"type %d, b_resid %d, b_bcount %d, b_bufsize %d\n",
buf, (uint32_t) buf->b_blkno / blks, buf->b_udf_c_type,
buf->b_resid, buf->b_bcount, buf->b_bufsize));
/* if we have FIDs fixup using buffer's sector number(s) */
if (buf->b_udf_c_type == UDF_C_FIDS) {
panic("UDF_C_FIDS in SHED_WRITING!\n");
buf_len = buf->b_bcount;
sectornr = our_sectornr;
bpos = 0;
while (buf_len) {
len = MIN(buf_len, sector_size);
fidblk = (uint8_t *) buf->b_data + bpos;
udf_fixup_fid_block(fidblk, sector_size,
0, len, sectornr);
sectornr++;
bpos += len;
buf_len -= len;
}
}
udf_fixup_node_internals(ump, buf->b_data, buf->b_udf_c_type);
VOP_STRATEGY(ump->devvp, buf);
return;
}
KASSERT(queue == UDF_SHED_SEQWRITING);
DPRINTF(SHEDULE, ("\nudf_issue_buf SEQWRITE %p : sector XXXX "
"type %d, b_resid %d, b_bcount %d, b_bufsize %d\n",
buf, buf->b_udf_c_type, buf->b_resid, buf->b_bcount,
buf->b_bufsize));
/*
* Buffers should not have been allocated to disc addresses yet on
* this queue. Note that a buffer can get multiple extents allocated.
*
* lmapping contains lb_num relative to base partition.
* pmapping contains lb_num as used for disc adressing.
*/
lmapping = ump->la_lmapping;
pmapping = ump->la_pmapping;
node_ad_cpy = ump->la_node_ad_cpy;
/* allocate buf and get its logical and physical mappings */
udf_late_allocate_buf(ump, buf, lmapping, pmapping, node_ad_cpy);
udf_VAT_mapping_update(ump, buf); /* XXX could pass *lmapping */
/* if we have FIDs, fixup using the new allocation table */
if (buf->b_udf_c_type == UDF_C_FIDS) {
buf_len = buf->b_bcount;
bpos = 0;
lmappos = lmapping;
while (buf_len) {
sectornr = *lmappos++;
len = MIN(buf_len, sector_size);
fidblk = (uint8_t *) buf->b_data + bpos;
udf_fixup_fid_block(fidblk, sector_size,
0, len, sectornr);
bpos += len;
buf_len -= len;
}
}
udf_fixup_node_internals(ump, buf->b_data, buf->b_udf_c_type);
VOP_STRATEGY(ump->devvp, buf);
}
static void
udf_doshedule(struct udf_mount *ump)
{
struct buf *buf;
struct timespec now, *last;
struct strat_private *priv = PRIV(ump);
void (*b_callback)(struct buf *);
int new_queue;
int error;
buf = BUFQ_GET(priv->queues[priv->cur_queue]);
if (buf) {
/* transfer from the current queue to the device queue */
mutex_exit(&priv->discstrat_mutex);
/* transform buffer to synchronous; XXX needed? */
b_callback = buf->b_iodone;
buf->b_iodone = NULL;
CLR(buf->b_flags, B_ASYNC);
/* issue and wait on completion */
udf_issue_buf(ump, priv->cur_queue, buf);
biowait(buf);
mutex_enter(&priv->discstrat_mutex);
/* if there is an error, repair this error, otherwise propagate */
if (buf->b_error && ((buf->b_flags & B_READ) == 0)) {
/* check what we need to do */
panic("UDF write error, can't handle yet!\n");
}
/* propagate result to higher layers */
if (b_callback) {
buf->b_iodone = b_callback;
(*buf->b_iodone)(buf);
}
return;
}
/* Check if we're idling in this state */
vfs_timestamp(&now);
last = &priv->last_queued[priv->cur_queue];
if (ump->discinfo.mmc_class == MMC_CLASS_CD) {
/* dont switch too fast for CD media; its expensive in time */
if (now.tv_sec - last->tv_sec < 3)
return;
}
/* check if we can/should switch */
new_queue = priv->cur_queue;
if (BUFQ_PEEK(priv->queues[UDF_SHED_READING]))
new_queue = UDF_SHED_READING;
if (BUFQ_PEEK(priv->queues[UDF_SHED_SEQWRITING]))
new_queue = UDF_SHED_SEQWRITING;
if (BUFQ_PEEK(priv->queues[UDF_SHED_WRITING])) /* only for unmount */
new_queue = UDF_SHED_WRITING;
if (priv->cur_queue == UDF_SHED_READING) {
if (new_queue == UDF_SHED_SEQWRITING) {
/* TODO use flag to signal if this is needed */
mutex_exit(&priv->discstrat_mutex);
/* update trackinfo for data and metadata */
error = udf_update_trackinfo(ump,
&ump->data_track);
assert(error == 0);
error = udf_update_trackinfo(ump,
&ump->metadata_track);
assert(error == 0);
mutex_enter(&priv->discstrat_mutex);
}
}
if (new_queue != priv->cur_queue) {
DPRINTF(SHEDULE, ("switching from %d to %d\n",
priv->cur_queue, new_queue));
}
priv->cur_queue = new_queue;
}
static void
udf_discstrat_thread(void *arg)
{
struct udf_mount *ump = (struct udf_mount *) arg;
struct strat_private *priv = PRIV(ump);
int empty;
empty = 1;
mutex_enter(&priv->discstrat_mutex);
while (priv->run_thread || !empty) {
/* process the current selected queue */
udf_doshedule(ump);
empty = (BUFQ_PEEK(priv->queues[UDF_SHED_READING]) == NULL);
empty &= (BUFQ_PEEK(priv->queues[UDF_SHED_WRITING]) == NULL);
empty &= (BUFQ_PEEK(priv->queues[UDF_SHED_SEQWRITING]) == NULL);
/* wait for more if needed */
if (empty)
cv_timedwait(&priv->discstrat_cv,
&priv->discstrat_mutex, hz/8);
}
mutex_exit(&priv->discstrat_mutex);
wakeup(&priv->run_thread);
kthread_exit(0);
/* not reached */
}
/* --------------------------------------------------------------------- */
static void
udf_discstrat_init_seq(struct udf_strat_args *args)
{
struct udf_mount *ump = args->ump;
struct strat_private *priv = PRIV(ump);
struct disk_strategy dkstrat;
uint32_t lb_size;
KASSERT(ump);
KASSERT(ump->logical_vol);
KASSERT(priv == NULL);
lb_size = udf_rw32(ump->logical_vol->lb_size);
KASSERT(lb_size > 0);
/* initialise our memory space */
ump->strategy_private = malloc(sizeof(struct strat_private),
M_UDFTEMP, M_WAITOK);
priv = ump->strategy_private;
memset(priv, 0 , sizeof(struct strat_private));
/* initialise locks */
cv_init(&priv->discstrat_cv, "udfstrat");
mutex_init(&priv->discstrat_mutex, MUTEX_DEFAULT, IPL_NONE);
/*
* Initialise pool for descriptors associated with nodes. This is done
* in lb_size units though currently lb_size is dictated to be
* sector_size.
*/
pool_init(&priv->desc_pool, lb_size, 0, 0, 0, "udf_desc_pool", NULL,
IPL_NONE);
/*
* remember old device strategy method and explicit set method
* `discsort' since we have our own more complex strategy that is not
* implementable on the CD device and other strategies will get in the
* way.
*/
memset(&priv->old_strategy_setting, 0,
sizeof(struct disk_strategy));
VOP_IOCTL(ump->devvp, DIOCGSTRATEGY, &priv->old_strategy_setting,
FREAD | FKIOCTL, NOCRED);
memset(&dkstrat, 0, sizeof(struct disk_strategy));
strcpy(dkstrat.dks_name, "discsort");
VOP_IOCTL(ump->devvp, DIOCSSTRATEGY, &dkstrat, FWRITE | FKIOCTL,
NOCRED);
/* initialise our internal sheduler */
priv->cur_queue = UDF_SHED_READING;
bufq_alloc(&priv->queues[UDF_SHED_READING], "disksort",
BUFQ_SORT_RAWBLOCK);
bufq_alloc(&priv->queues[UDF_SHED_WRITING], "disksort",
BUFQ_SORT_RAWBLOCK);
bufq_alloc(&priv->queues[UDF_SHED_SEQWRITING], "fcfs", 0);
vfs_timestamp(&priv->last_queued[UDF_SHED_READING]);
vfs_timestamp(&priv->last_queued[UDF_SHED_WRITING]);
vfs_timestamp(&priv->last_queued[UDF_SHED_SEQWRITING]);
/* create our disk strategy thread */
priv->run_thread = 1;
if (kthread_create(PRI_NONE, 0 /* KTHREAD_MPSAFE*/, NULL /* cpu_info*/,
udf_discstrat_thread, ump, &priv->queue_lwp,
"%s", "udf_rw")) {
panic("fork udf_rw");
}
}
static void
udf_discstrat_finish_seq(struct udf_strat_args *args)
{
struct udf_mount *ump = args->ump;
struct strat_private *priv = PRIV(ump);
int error;
if (ump == NULL)
return;
/* stop our sheduling thread */
KASSERT(priv->run_thread == 1);
priv->run_thread = 0;
wakeup(priv->queue_lwp);
do {
error = tsleep(&priv->run_thread, PRIBIO+1,
"udfshedfin", hz);
} while (error);
/* kthread should be finished now */
/* set back old device strategy method */
VOP_IOCTL(ump->devvp, DIOCSSTRATEGY, &priv->old_strategy_setting,
FWRITE, NOCRED);
/* destroy our pool */
pool_destroy(&priv->desc_pool);
/* free our private space */
free(ump->strategy_private, M_UDFTEMP);
ump->strategy_private = NULL;
}
/* --------------------------------------------------------------------- */
struct udf_strategy udf_strat_sequential =
{
udf_create_logvol_dscr_seq,
udf_free_logvol_dscr_seq,
udf_read_logvol_dscr_seq,
udf_write_logvol_dscr_seq,
udf_queuebuf_seq,
udf_discstrat_init_seq,
udf_discstrat_finish_seq
};

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
/* $NetBSD: udf_subr.h,v 1.4 2006/03/05 16:55:44 christos Exp $ */
/* $NetBSD: udf_subr.h,v 1.5 2008/05/14 16:49:48 reinoud Exp $ */
/*
* Copyright (c) 2006 Reinoud Zandijk
* Copyright (c) 2006, 2008 Reinoud Zandijk
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -12,13 +12,6 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the
* NetBSD Project. See http://www.NetBSD.org/ for
* information about NetBSD.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
@ -33,52 +26,157 @@
*
*/
#ifndef _FS_UDF_UDF_SUBR_H_
#define _FS_UDF_UDF_SUBR_H_
/* handies */
#define VFSTOUDF(mp) ((struct udf_mount *)mp->mnt_data)
/* device information updating */
int udf_update_trackinfo(struct udf_mount *ump, struct mmc_trackinfo *trackinfo);
int udf_update_discinfo(struct udf_mount *ump);
int udf_search_tracks(struct udf_mount *ump, struct udf_args *args,
int *first_tracknr, int *last_tracknr);
int udf_search_writing_tracks(struct udf_mount *ump);
int udf_setup_writeparams(struct udf_mount *ump);
int udf_synchronise_caches(struct udf_mount *ump);
/* tags and read/write descriptors */
/* tags operations */
int udf_fidsize(struct fileid_desc *fid);
int udf_check_tag(void *blob);
int udf_check_tag_payload(void *blob, uint32_t max_length);
int udf_validate_tag_sum(void *blob);
int udf_validate_tag_and_crc_sums(void *blob);
void udf_validate_tag_sum(void *blob);
void udf_validate_tag_and_crc_sums(void *blob);
int udf_tagsize(union dscrptr *dscr, uint32_t udf_sector_size);
int udf_read_descriptor(
/* read/write descriptors */
int udf_read_phys_dscr(
struct udf_mount *ump,
uint32_t sector,
struct malloc_type *mtype, /* where to allocate */
union dscrptr **dstp); /* out */
int udf_write_phys_dscr_sync(struct udf_mount *ump, struct udf_node *udf_node,
int what, union dscrptr *dscr,
uint32_t sector, uint32_t logsector);
int udf_write_phys_dscr_async(struct udf_mount *ump, struct udf_node *udf_node,
int what, union dscrptr *dscr,
uint32_t sector, uint32_t logsector,
void (*dscrwr_callback)(struct buf *));
/* read/write node descriptors */
int udf_create_logvol_dscr(struct udf_mount *ump, struct udf_node *udf_node,
struct long_ad *icb, union dscrptr **dscrptr);
void udf_free_logvol_dscr(struct udf_mount *ump, struct long_ad *icb_loc,
void *dscr);
int udf_read_logvol_dscr(struct udf_mount *ump, struct long_ad *icb,
union dscrptr **dscrptr);
int udf_write_logvol_dscr(struct udf_node *udf_node, union dscrptr *dscr,
struct long_ad *icb, int waitfor);
/* volume descriptors readers and checkers */
int udf_read_anchors(struct udf_mount *ump, struct udf_args *args);
int udf_read_anchors(struct udf_mount *ump);
int udf_read_vds_space(struct udf_mount *ump);
int udf_process_vds(struct udf_mount *ump, struct udf_args *args);
int udf_read_vds_tables(struct udf_mount *ump, struct udf_args *args);
int udf_read_rootdirs(struct udf_mount *ump, struct udf_args *args);
int udf_process_vds(struct udf_mount *ump);
int udf_read_vds_tables(struct udf_mount *ump);
int udf_read_rootdirs(struct udf_mount *ump);
/* open/close and sync volumes */
int udf_open_logvol(struct udf_mount *ump);
int udf_close_logvol(struct udf_mount *ump, int mntflags);
int udf_writeout_vat(struct udf_mount *ump);
int udf_write_partition_spacetables(struct udf_mount *ump, int waitfor);
void udf_do_sync(struct udf_mount *ump, kauth_cred_t cred, int waitfor);
/* translation services */
int udf_translate_vtop(struct udf_mount *ump, struct long_ad *icb_loc, uint32_t *lb_numres, uint32_t *extres);
int udf_translate_file_extent(struct udf_node *node, uint32_t from, uint32_t pages, uint64_t *map);
int udf_translate_vtop(struct udf_mount *ump, struct long_ad *icb_loc,
uint32_t *lb_numres, uint32_t *extres);
int udf_translate_file_extent(struct udf_node *node,
uint32_t from, uint32_t num_lb, uint64_t *map);
void udf_get_adslot(struct udf_node *udf_node, int slot, struct long_ad *icb, int *eof);
int udf_append_adslot(struct udf_node *udf_node, int slot, struct long_ad *icb);
int udf_vat_read(struct udf_node *vat_node, uint8_t *blob, int size, uint32_t offset);
int udf_vat_write(struct udf_node *vat_node, uint8_t *blob, int size, uint32_t offset);
/* disc allocation */
void udf_late_allocate_buf(struct udf_mount *ump, struct buf *buf, uint64_t *lmapping, uint64_t *pmapping, struct long_ad *node_ad_cpy);
void udf_free_allocated_space(struct udf_mount *ump, uint32_t lb_num, uint16_t vpart_num, uint32_t num_lb);
int udf_pre_allocate_space(struct udf_mount *ump, int udf_c_type, int num_lb, uint16_t *alloc_partp, uint64_t *lmapping, uint64_t *pmapping);
int udf_grow_node(struct udf_node *node, uint64_t new_size);
int udf_shrink_node(struct udf_node *node, uint64_t new_size);
/* node readers and writers */
int udf_get_node(struct udf_mount *ump, struct long_ad *icbloc, struct udf_node **noderes);
int udf_dispose_node(struct udf_node *node);
int udf_dispose_locked_node(struct udf_node *node);
void udf_read_filebuf(struct udf_node *node, struct buf *buf);
int udf_read_file_extent(struct udf_node *node, uint32_t from, uint32_t sectors, uint8_t *blob);
uint64_t udf_advance_uniqueid(struct udf_mount *ump);
/* directory read and parse utils */
void udf_to_unix_name(char *result, char *id, int len, struct charspec *chsp);
void unix_to_udf_name(char *result, char *name, uint8_t *result_len, struct charspec *chsp);
int udf_lookup_name_in_dir(struct vnode *vp, const char *name, int namelen, struct long_ad *icb_loc);
#define UDF_LOCK_NODE(udf_node, flag) udf_lock_node(udf_node, (flag), __FILE__, __LINE__)
#define UDF_UNLOCK_NODE(udf_node, flag) udf_unlock_node(udf_node, (flag))
void udf_lock_node(struct udf_node *udf_node, int flag, char const *fname, const int lineno);
void udf_unlock_node(struct udf_node *udf_node, int flag);
int udf_get_node(struct udf_mount *ump, struct long_ad *icbloc, struct udf_node **noderes);
int udf_writeout_node(struct udf_node *udf_node, int waitfor);
int udf_dispose_node(struct udf_node *node);
/* node ops */
int udf_resize_node(struct udf_node *node, uint64_t new_size, int *extended);
int udf_extattr_search_intern(struct udf_node *node, uint32_t sattr, char const *sattrname, uint32_t *offsetp, uint32_t *lengthp);
/* node data buffer read/write */
void udf_read_filebuf(struct udf_node *node, struct buf *buf);
void udf_write_filebuf(struct udf_node *node, struct buf *buf);
void udf_fixup_fid_block(uint8_t *blob, int lb_size, int rfix_pos, int max_rfix_pos, uint32_t lb_num);
void udf_fixup_internal_extattr(uint8_t *blob, uint32_t lb_num);
void udf_fixup_node_internals(struct udf_mount *ump, uint8_t *blob, int udf_c_type);
/* device strategy */
void udf_discstrat_init(struct udf_mount *ump);
void udf_discstrat_finish(struct udf_mount *ump);
void udf_discstrat_queuebuf(struct udf_mount *ump, struct buf *nestbuf);
/* structure writers */
int udf_write_terminator(struct udf_mount *ump, uint32_t sector);
/* structure creators */
void udf_set_regid(struct regid *regid, char const *name);
void udf_add_domain_regid(struct udf_mount *ump, struct regid *regid);
void udf_add_udf_regid(struct udf_mount *ump, struct regid *regid);
void udf_add_impl_regid(struct udf_mount *ump, struct regid *regid);
void udf_add_app_regid(struct udf_mount *ump, struct regid *regid);
/* directory operations and helpers */
void udf_osta_charset(struct charspec *charspec);
int udf_read_fid_stream(struct vnode *vp, uint64_t *offset, struct fileid_desc *fid, struct dirent *dirent);
int udf_lookup_name_in_dir(struct vnode *vp, const char *name, int namelen, struct long_ad *icb_loc);
int udf_create_node(struct vnode *dvp, struct vnode **vpp, struct vattr *vap, struct componentname *cnp);
void udf_delete_node(struct udf_node *udf_node);
int udf_chsize(struct vnode *vp, u_quad_t newsize, kauth_cred_t cred);
int udf_dir_detach(struct udf_mount *ump, struct udf_node *dir_node, struct udf_node *udf_node, struct componentname *cnp);
int udf_dir_attach(struct udf_mount *ump, struct udf_node *dir_node, struct udf_node *udf_node, struct vattr *vap, struct componentname *cnp);
/* update and times */
void udf_add_to_dirtylist(struct udf_node *udf_node);
void udf_remove_from_dirtylist(struct udf_node *udf_node);
void udf_itimes(struct udf_node *udf_node, struct timespec *acc,
struct timespec *mod, struct timespec *changed);
int udf_update(struct vnode *node, struct timespec *acc,
struct timespec *mod, int updflags);
/* helpers and converters */
long udf_calchash(struct long_ad *icbptr); /* for `inode' numbering */
uint32_t udf_getaccessmode(struct udf_node *node);
void udf_setaccessmode(struct udf_node *udf_node, mode_t mode);
void udf_getownership(struct udf_node *udf_node, uid_t *uidp, gid_t *gidp);
void udf_setownership(struct udf_node *udf_node, uid_t uid, gid_t gid);
void udf_to_unix_name(char *result, char *id, int len, struct charspec *chsp);
void unix_to_udf_name(char *result, uint8_t *result_len, char const *name, int name_len, struct charspec *chsp);
void udf_timestamp_to_timespec(struct udf_mount *ump, struct timestamp *timestamp, struct timespec *timespec);
void udf_timespec_to_timestamp(struct timespec *timespec, struct timestamp *timestamp);
/* vnode operations */
int udf_inactive(void *v);
@ -93,7 +191,7 @@ int udf_access(void *v);
int udf_read(void *v);
int udf_write(void *v);
int udf_trivial_bmap(void *v);
int udf_strategy(void *v);
int udf_vfsstrategy(void *v);
int udf_lookup(void *v);
int udf_create(void *v);
int udf_mknod(void *v);
@ -107,10 +205,4 @@ int udf_rmdir(void *v);
int udf_fsync(void *v);
int udf_advlock(void *v);
/* helpers and converters */
long udf_calchash(struct long_ad *icbptr); /* for `inode' numbering */
uint32_t udf_getaccessmode(struct udf_node *node);
void udf_timestamp_to_timespec(struct udf_mount *ump, struct timestamp *timestamp, struct timespec *timespec);
#endif /* !_FS_UDF_UDF_SUBR_H_ */

View File

@ -1,7 +1,7 @@
/* $NetBSD: udf_vfsops.c,v 1.37 2008/05/10 02:26:09 rumble Exp $ */
/* $NetBSD: udf_vfsops.c,v 1.38 2008/05/14 16:49:48 reinoud Exp $ */
/*
* Copyright (c) 2006 Reinoud Zandijk
* Copyright (c) 2006, 2008 Reinoud Zandijk
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -12,13 +12,6 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the
* NetBSD Project. See http://www.NetBSD.org/ for
* information about NetBSD.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
@ -33,16 +26,16 @@
*
*/
#include <sys/cdefs.h>
#ifndef lint
__KERNEL_RCSID(0, "$NetBSD: udf_vfsops.c,v 1.37 2008/05/10 02:26:09 rumble Exp $");
__KERNEL_RCSID(0, "$NetBSD: udf_vfsops.c,v 1.38 2008/05/14 16:49:48 reinoud Exp $");
#endif /* not lint */
#if defined(_KERNEL_OPT)
#include "opt_quota.h"
#include "opt_compat_netbsd.h"
#include "opt_udf.h"
#endif
#include <sys/param.h>
@ -76,6 +69,8 @@ __KERNEL_RCSID(0, "$NetBSD: udf_vfsops.c,v 1.37 2008/05/10 02:26:09 rumble Exp $
MODULE(MODULE_CLASS_VFS, udf, NULL);
#define VTOI(vnode) ((struct udf_node *) vnode->v_data)
/* verbose levels of the udf filingsystem */
int udf_verbose = UDF_DEBUGGING;
@ -91,13 +86,6 @@ VFS_PROTOS(udf);
/* internal functions */
static int udf_mountfs(struct vnode *, struct mount *, struct lwp *, struct udf_args *);
#if 0
static int update_mp(struct mount *, struct udf_args *);
#endif
/* handies */
#define VFSTOUDF(mp) ((struct udf_mount *)mp->mnt_data)
/* --------------------------------------------------------------------- */
@ -140,20 +128,6 @@ struct vfsops udf_vfsops = {
{ NULL, NULL, }, /* LIST_ENTRY(vfsops) */
};
static int
udf_modcmd(modcmd_t cmd, void *arg)
{
switch (cmd) {
case MODULE_CMD_INIT:
return vfs_attach(&udf_vfsops);
case MODULE_CMD_FINI:
return vfs_detach(&udf_vfsops);
default:
return ENOTTY;
}
}
/* --------------------------------------------------------------------- */
/* file system starts here */
@ -172,7 +146,6 @@ udf_init(void)
IPL_NONE);
}
/* --------------------------------------------------------------------- */
void
udf_reinit(void)
@ -181,7 +154,6 @@ udf_reinit(void)
/* reinit pool? */
}
/* --------------------------------------------------------------------- */
void
udf_done(void)
@ -194,6 +166,21 @@ udf_done(void)
malloc_type_detach(M_UDFTEMP);
}
static int
udf_modcmd(modcmd_t cmd, void *arg)
{
switch (cmd) {
case MODULE_CMD_INIT:
return vfs_attach(&udf_vfsops);
case MODULE_CMD_FINI:
return vfs_detach(&udf_vfsops);
default:
return ENOTTY;
}
}
/* --------------------------------------------------------------------- */
int
@ -217,23 +204,6 @@ free_udf_mountinfo(struct mount *mp)
ump = VFSTOUDF(mp);
if (ump) {
/* dereference all system nodes */
if (ump->metadata_file)
vrele(ump->metadata_file->vnode);
if (ump->metadatamirror_file)
vrele(ump->metadatamirror_file->vnode);
if (ump->metadatabitmap_file)
vrele(ump->metadatabitmap_file->vnode);
/* vflush all (system) nodes if any */
(void) vflush(mp, NULLVP, FORCECLOSE);
/* dispose of our descriptor pool */
if (ump->desc_pool) {
pool_destroy(ump->desc_pool);
free(ump->desc_pool, M_UDFMNT);
}
/* clear our data */
for (i = 0; i < UDF_ANCHORS; i++)
MPFREE(ump->anchors[i], M_UDFVOLD);
@ -242,14 +212,25 @@ free_udf_mountinfo(struct mount *mp)
MPFREE(ump->unallocated, M_UDFVOLD);
MPFREE(ump->implementation, M_UDFVOLD);
MPFREE(ump->logvol_integrity, M_UDFVOLD);
for (i = 0; i < UDF_PARTITIONS; i++)
for (i = 0; i < UDF_PARTITIONS; i++) {
MPFREE(ump->partitions[i], M_UDFVOLD);
MPFREE(ump->part_unalloc_dscr[i], M_UDFVOLD);
MPFREE(ump->part_freed_dscr[i], M_UDFVOLD);
}
MPFREE(ump->fileset_desc, M_UDFVOLD);
MPFREE(ump->vat_table, M_UDFVOLD);
MPFREE(ump->sparing_table, M_UDFVOLD);
MPFREE(ump->metadata_bitmap.bits, M_UDFVOLD);
MPFREE(ump->la_node_ad_cpy, M_UDFMNT);
MPFREE(ump->la_pmapping, M_TEMP);
MPFREE(ump->la_lmapping, M_TEMP);
mutex_destroy(&ump->ihash_lock);
mutex_destroy(&ump->get_node_lock);
mutex_destroy(&ump->allocate_mutex);
MPFREE(ump->vat_table, M_UDFVOLD);
free(ump, M_UDFMNT);
}
}
@ -257,6 +238,35 @@ free_udf_mountinfo(struct mount *mp)
/* --------------------------------------------------------------------- */
/* if the system nodes exist, release them */
static void
udf_release_system_nodes(struct mount *mp)
{
struct udf_mount *ump = VFSTOUDF(mp);
int error;
/* if we haven't even got an ump, dont bother */
if (!ump)
return;
/* VAT partition support */
if (ump->vat_node)
vrele(ump->vat_node->vnode);
/* Metadata partition support */
if (ump->metadata_node)
vrele(ump->metadata_node->vnode);
if (ump->metadatamirror_node)
vrele(ump->metadatamirror_node->vnode);
if (ump->metadatabitmap_node)
vrele(ump->metadatabitmap_node->vnode);
/* This flush should NOT write anything nor allow any node to remain */
if ((error = vflush(ump->vfs_mountp, NULLVP, 0)) != 0)
panic("Failure to flush UDF system vnodes\n");
}
int
udf_mount(struct mount *mp, const char *path,
void *data, size_t *data_len)
@ -320,8 +330,14 @@ udf_mount(struct mount *mp, const char *path,
return ENXIO;
}
#ifndef UDF_READWRITE
/* force read-only for now */
mp->mnt_flag |= MNT_RDONLY;
if ((mp->mnt_flag & MNT_RDONLY) == 0) {
printf("Enable kernel option UDF_READWRITE for writing\n");
vrele(devvp);
return EROFS;
}
#endif
/*
* If mount by non-root, then verify that user has necessary
@ -353,6 +369,9 @@ udf_mount(struct mount *mp, const char *path,
/* opened ok, try mounting */
error = udf_mountfs(devvp, mp, l, args);
if (error) {
udf_release_system_nodes(mp);
/* cleanup */
udf_discstrat_finish(VFSTOUDF(mp));
free_udf_mountinfo(mp);
vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
(void) VOP_CLOSE(devvp, openflags, NOCRED);
@ -371,8 +390,23 @@ udf_mount(struct mount *mp, const char *path,
/* successfully mounted */
DPRINTF(VOLUMES, ("udf_mount() successfull\n"));
return set_statvfs_info(path, UIO_USERSPACE, args->fspec, UIO_USERSPACE,
error = set_statvfs_info(path, UIO_USERSPACE, args->fspec, UIO_USERSPACE,
mp->mnt_op->vfs_name, mp, l);
if (error)
return error;
/* If we're not opened read-only, open its logical volume */
if ((mp->mnt_flag & MNT_RDONLY) == 0) {
if ((error = udf_open_logvol(VFSTOUDF(mp))) != 0) {
printf( "mount_udf: can't open logical volume for "
"writing,downgrading access to read-only\n");
mp->mnt_flag |= MNT_RDONLY;
/* FIXME we can't return error now on open failure */
return 0;
}
}
return 0;
}
/* --------------------------------------------------------------------- */
@ -423,16 +457,38 @@ udf_unmount(struct mount *mp, int mntflags)
if ((error = vflush(mp, NULLVP, flags | SKIPSYSTEM)) != 0)
return error;
/* update nodes and wait for completion of writeout of system nodes */
udf_sync(mp, FSYNC_WAIT, NOCRED);
#ifdef DEBUG
if (udf_verbose & UDF_DEBUG_LOCKING)
udf_unmount_sanity_check(mp);
#endif
DPRINTF(VOLUMES, ("flush OK\n"));
/* flush again, to check if we are still busy for something else */
if ((error = vflush(ump->vfs_mountp, NULLVP, flags | SKIPSYSTEM)) != 0)
return error;
/*
* TODO close logical volume and close session if requested.
*/
DPRINTF(VOLUMES, ("flush OK on unmount\n"));
/* close logical volume and close session if requested */
if ((error = udf_close_logvol(ump, mntflags)) != 0)
return error;
#ifdef DEBUG
DPRINTF(VOLUMES, ("FINAL sanity check\n"));
if (udf_verbose & UDF_DEBUG_LOCKING)
udf_unmount_sanity_check(mp);
#endif
/* NOTE release system nodes should NOT write anything */
udf_release_system_nodes(mp);
/* finalise disc strategy */
udf_discstrat_finish(ump);
/* synchronise device caches */
(void) udf_synchronise_caches(ump);
/* close device */
DPRINTF(VOLUMES, ("closing device\n"));
@ -454,10 +510,10 @@ udf_unmount(struct mount *mp, int mntflags)
ump->devvp->v_specmountpoint = NULL;
vput(ump->devvp);
/* free up umt structure */
/* free our ump */
free_udf_mountinfo(mp);
/* free ump struct reference */
/* free ump struct references */
mp->mnt_data = NULL;
mp->mnt_flag &= ~MNT_LOCAL;
@ -477,20 +533,32 @@ udf_mountfs(struct vnode *devvp, struct mount *mp,
{
struct udf_mount *ump;
uint32_t sector_size, lb_size, bshift;
uint32_t logvol_integrity;
int num_anchors, error, lst;
/* flush out any old buffers remaining from a previous use. */
if ((error = vinvalbuf(devvp, V_SAVE, l->l_cred, l, 0, 0)))
return error;
/* setup basic mount information */
mp->mnt_data = NULL;
mp->mnt_stat.f_fsidx.__fsid_val[0] = (uint32_t) devvp->v_rdev;
mp->mnt_stat.f_fsidx.__fsid_val[1] = makefstype(MOUNT_UDF);
mp->mnt_stat.f_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0];
mp->mnt_stat.f_namemax = UDF_MAX_NAMELEN;
mp->mnt_flag |= MNT_LOCAL;
/* allocate udf part of mount structure; malloc always succeeds */
ump = malloc(sizeof(struct udf_mount), M_UDFMNT, M_WAITOK | M_ZERO);
/* init locks */
mutex_init(&ump->logvol_mutex, MUTEX_DEFAULT, IPL_NONE);
mutex_init(&ump->ihash_lock, MUTEX_DEFAULT, IPL_NONE);
mutex_init(&ump->get_node_lock, MUTEX_DEFAULT, IPL_NONE);
mutex_init(&ump->allocate_mutex, MUTEX_DEFAULT, IPL_NONE);
cv_init(&ump->dirtynodes_cv, "udfsync2");
/* init `ino_t' to udf_node hash table */
/* init `ino_t' to udf_node hash table and other lists */
for (lst = 0; lst < UDF_INODE_HASHSIZE; lst++) {
LIST_INIT(&ump->udf_nodes[lst]);
}
@ -518,10 +586,29 @@ udf_mountfs(struct vnode *devvp, struct mount *mp,
return EIO;
}
/*
* Inspect if we're asked to mount read-write on a non recordable or
* closed sequential disc.
*/
if ((mp->mnt_flag & MNT_RDONLY) == 0) {
if ((ump->discinfo.mmc_cur & MMC_CAP_RECORDABLE) == 0) {
printf("UDF mount: disc is not recordable\n");
return EROFS;
}
/*
* TODO if on sequential media and last session is closed,
* check for enough space to open/close new session
*/
}
/* initialise bootstrap disc strategy */
ump->strategy = &udf_strat_bootstrap;
udf_discstrat_init(ump);
/* read all anchors to get volume descriptor sequence */
num_anchors = udf_read_anchors(ump, args);
num_anchors = udf_read_anchors(ump);
if (num_anchors == 0)
return ENOENT;
return EINVAL;
DPRINTF(VOLUMES, ("Read %d anchors on this disc, session %d\n",
num_anchors, args->sessionnr));
@ -532,50 +619,63 @@ udf_mountfs(struct vnode *devvp, struct mount *mp,
return error;
}
/* close down (direct) disc strategy */
udf_discstrat_finish(ump);
/* check consistency and completeness */
if ((error = udf_process_vds(ump, args))) {
if ((error = udf_process_vds(ump))) {
printf( "UDF mount: disc not properly formatted"
"(bad VDS)\n");
return error;
}
/*
* Initialise pool for descriptors associated with nodes. This is done
* in lb_size units though currently lb_size is dictated to be
* sector_size.
*/
lb_size = udf_rw32(ump->logical_vol->lb_size);
ump->desc_pool = malloc(sizeof(struct pool), M_UDFMNT, M_WAITOK);
memset(ump->desc_pool, 0, sizeof(struct pool));
pool_init(ump->desc_pool, lb_size, 0, 0, 0, "udf_desc_pool", NULL,
IPL_NONE);
/* switch to new disc strategy */
KASSERT(ump->strategy != &udf_strat_bootstrap);
udf_discstrat_init(ump);
/* initialise late allocation administration space */
ump->la_lmapping = malloc(sizeof(uint64_t) * UDF_MAX_MAPPINGS,
M_TEMP, M_WAITOK);
ump->la_pmapping = malloc(sizeof(uint64_t) * UDF_MAX_MAPPINGS,
M_TEMP, M_WAITOK);
/* setup node cleanup extents copy space */
lb_size = udf_rw32(ump->logical_vol->lb_size);
ump->la_node_ad_cpy = malloc(lb_size * UDF_MAX_ALLOC_EXTENTS,
M_UDFMNT, M_WAITOK);
memset(ump->la_node_ad_cpy, 0, lb_size * UDF_MAX_ALLOC_EXTENTS);
/* setup rest of mount information */
mp->mnt_data = ump;
/* bshift is allways equal to disc sector size */
mp->mnt_dev_bshift = bshift;
mp->mnt_fs_bshift = bshift;
/* note that the mp info needs to be initialised for reading! */
/* read vds support tables like VAT, sparable etc. */
if ((error = udf_read_vds_tables(ump, args))) {
if ((error = udf_read_vds_tables(ump))) {
printf( "UDF mount: error in format or damaged disc "
"(VDS tables failing)\n");
return error;
}
if ((error = udf_read_rootdirs(ump, args))) {
/* check if volume integrity is closed otherwise its dirty */
logvol_integrity = udf_rw32(ump->logvol_integrity->integrity_type);
if (logvol_integrity != UDF_INTEGRITY_CLOSED) {
printf("UDF mount: file system is not clean; ");
printf("please fsck(8)\n");
return EPERM;
}
/* read root directory */
if ((error = udf_read_rootdirs(ump))) {
printf( "UDF mount: "
"disc not properly formatted or damaged disc "
"(rootdirs failing)\n");
return error;
}
/* setup rest of mount information */
mp->mnt_data = ump;
mp->mnt_stat.f_fsidx.__fsid_val[0] = (uint32_t) devvp->v_rdev;
mp->mnt_stat.f_fsidx.__fsid_val[1] = makefstype(MOUNT_UDF);
mp->mnt_stat.f_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0];
mp->mnt_stat.f_namemax = UDF_MAX_NAMELEN;
mp->mnt_flag |= MNT_LOCAL;
/* bshift is always equal to disc sector size */
mp->mnt_dev_bshift = bshift;
mp->mnt_fs_bshift = bshift;
/* do we have to set this? */
devvp->v_specmountpoint = mp;
@ -638,14 +738,23 @@ udf_statvfs(struct mount *mp, struct statvfs *sbp)
sbp->f_frsize = ump->discinfo.sector_size;
sbp->f_iosize = ump->discinfo.sector_size;
/* TODO integrity locking */
/* free and used space for mountpoint based on logvol integrity */
mutex_enter(&ump->allocate_mutex);
lvid = ump->logvol_integrity;
if (lvid) {
num_part = udf_rw32(lvid->num_part);
impl = (struct udf_logvol_info *) (lvid->tables + 2*num_part);
freeblks = sizeblks = 0;
freeblks = sizeblks = 0;
/* Sequentials report free space directly (CD/DVD/BD-R) */
KASSERT(lvid);
num_part = udf_rw32(lvid->num_part);
impl = (struct udf_logvol_info *) (lvid->tables + 2*num_part);
if (ump->discinfo.mmc_cur & MMC_CAP_SEQUENTIAL) {
/* XXX assumption at most two tracks open */
freeblks = ump->data_track.free_blocks;
if (ump->data_track.tracknr != ump->metadata_track.tracknr)
freeblks += ump->metadata_track.free_blocks;
sizeblks = ump->discinfo.last_possible_lba;
} else {
/* free and used space for mountpoint based on logvol integrity */
for (part=0; part < num_part; part++) {
pos1 = &lvid->tables[0] + part;
pos2 = &lvid->tables[0] + num_part + part;
@ -654,33 +763,79 @@ udf_statvfs(struct mount *mp, struct statvfs *sbp)
sizeblks += udf_rw32(*pos2);
}
}
sbp->f_blocks = sizeblks;
sbp->f_bfree = freeblks;
}
freeblks -= ump->uncomitted_lb;
sbp->f_blocks = sizeblks;
sbp->f_bfree = freeblks;
sbp->f_files = 0;
if (impl) {
sbp->f_files = udf_rw32(impl->num_files);
sbp->f_files += udf_rw32(impl->num_directories);
/* XXX read only for now XXX */
sbp->f_bavail = 0;
sbp->f_bresvd = 0;
/* tricky, next only aplies to ffs i think, so set to zero */
sbp->f_ffree = 0;
sbp->f_favail = 0;
sbp->f_fresvd = 0;
}
/* XXX read only for now XXX */
sbp->f_bavail = 0;
sbp->f_bresvd = 0;
/* tricky, next only aplies to ffs i think, so set to zero */
sbp->f_ffree = 0;
sbp->f_favail = 0;
sbp->f_fresvd = 0;
mutex_exit(&ump->allocate_mutex);
copy_statvfs_info(sbp, mp);
return 0;
}
/* --------------------------------------------------------------------- */
/*
* TODO what about writing out free space maps, lvid etc? only on `waitfor'
* i.e. explicit syncing by the user?
*/
int
udf_sync(struct mount *mp, int waitfor,
kauth_cred_t cred)
udf_sync(struct mount *mp, int waitfor, kauth_cred_t cred)
{
struct udf_mount *ump = VFSTOUDF(mp);
int error;
DPRINTF(CALL, ("udf_sync called\n"));
/* nothing to be done as upto now read-only */
/* if called when mounted readonly, just ignore */
if (mp->mnt_flag & MNT_RDONLY)
return 0;
if (ump->syncing && !waitfor) {
printf("UDF: skipping autosync\n");
return 0;
}
/* get sync lock */
ump->syncing = 1;
udf_do_sync(ump, cred, waitfor);
if (waitfor == MNT_WAIT) {
/* XXX lock for VAT en bitmaps? */
/* metadata nodes are written synchronous */
DPRINTF(CALL, ("udf_sync: syncing metadata\n"));
if (ump->lvclose & UDF_WRITE_VAT)
udf_writeout_vat(ump);
if (ump->lvclose & UDF_WRITE_PART_BITMAPS) {
error = udf_write_partition_spacetables(ump, waitfor);
if (error) {
printf( "udf_close_logvol: writeout of space "
"tables failed\n");
}
ump->lvclose &= ~UDF_WRITE_PART_BITMAPS;
}
}
DPRINTF(CALL, ("end of udf_sync()\n"));
ump->syncing = 0;
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
# $NetBSD: Makefile,v 1.1 2006/02/02 15:19:16 reinoud Exp $
# $NetBSD: Makefile,v 1.2 2008/05/14 16:49:48 reinoud Exp $
.include "../Makefile.inc"
@ -7,6 +7,12 @@
KMOD= udf
SRCS= lkminit_vfs.c
SRCS+= udf_osta.c udf_subr.c udf_vfsops.c udf_vnops.c
SRCS+= udf_osta.c udf_subr.c udf_vfsops.c udf_vnops.c \
udf_readwrite.c udf_strat_bootstrap.c udf_strat_direct.c \
udf_strat_sequential.c udf_strat_rmw.c udf_allocation.c
CFLAGS+= -DLKM
CFLAGS+= -DPOOL_DIAGNOSTICS
CFLAGS+= -DUDF_READWRITE
.include <bsd.kmod.mk>

View File

@ -1,4 +1,4 @@
/* $NetBSD: genfs_io.c,v 1.6 2008/04/19 11:53:13 hannken Exp $ */
/* $NetBSD: genfs_io.c,v 1.7 2008/05/14 16:49:47 reinoud Exp $ */
/*
* Copyright (c) 1982, 1986, 1989, 1993
@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: genfs_io.c,v 1.6 2008/04/19 11:53:13 hannken Exp $");
__KERNEL_RCSID(0, "$NetBSD: genfs_io.c,v 1.7 2008/05/14 16:49:47 reinoud Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -1211,6 +1211,29 @@ genfs_gop_write(struct vnode *vp, struct vm_page **pgs, int npages, int flags)
return error;
}
int
genfs_gop_write_rwmap(struct vnode *vp, struct vm_page **pgs, int npages, int flags)
{
off_t off;
vaddr_t kva;
size_t len;
int error;
UVMHIST_FUNC(__func__); UVMHIST_CALLED(ubchist);
UVMHIST_LOG(ubchist, "vp %p pgs %p npages %d flags 0x%x",
vp, pgs, npages, flags);
off = pgs[0]->offset;
kva = uvm_pagermapin(pgs, npages,
UVMPAGER_MAPIN_READ | UVMPAGER_MAPIN_WAITOK);
len = npages << PAGE_SHIFT;
error = genfs_do_io(vp, off, kva, len, flags, UIO_WRITE,
uvm_aio_biodone);
return error;
}
/*
* Backend routine for doing I/O to vnode pages. Pages are already locked
* and mapped into kernel memory. Here we just look up the underlying

View File

@ -1,4 +1,4 @@
/* $NetBSD: genfs_node.h,v 1.16 2007/02/20 16:19:42 ad Exp $ */
/* $NetBSD: genfs_node.h,v 1.17 2008/05/14 16:49:47 reinoud Exp $ */
/*
* Copyright (c) 2001 Chuck Silvers.
@ -85,6 +85,7 @@ void genfs_size(struct vnode *, off_t, off_t *, int);
void genfs_node_init(struct vnode *, const struct genfs_ops *);
void genfs_node_destroy(struct vnode *);
int genfs_gop_write(struct vnode *, struct vm_page **, int, int);
int genfs_gop_write_rwmap(struct vnode *, struct vm_page **, int, int);
int genfs_compat_gop_write(struct vnode *, struct vm_page **, int, int);
void genfs_directio(struct vnode *, struct uio *, int);

View File

@ -1,4 +1,4 @@
# $NetBSD: Makefile,v 1.232 2008/04/15 11:17:48 plunky Exp $
# $NetBSD: Makefile,v 1.233 2008/05/14 16:49:47 reinoud Exp $
# from: @(#)Makefile 5.20 (Berkeley) 6/12/93
.include <bsd.own.mk>
@ -11,7 +11,7 @@ SUBDIR= ac accton acpitools altq amd apm apmd arp bad144 bind bootp \
grfconfig grfinfo gspa hilinfo ifwatchd inetd installboot \
iopctl iostat ipwctl irdaattach isdn iteconfig iwictl\
kgmon lastlogin link lmcconfig lockstat lpr mailwrapper makefs \
map-mbone mdconfig memswitch mlxctl mopd mountd moused \
map-mbone mdconfig memswitch mlxctl mmcformat mopd mountd moused \
mrinfo mrouted mscdlabel mtrace \
mtree ndbootd ndiscvt netgroup_mkdb nfsd ntp ofctl paxctl pcictl \
pkg_install \

View File

@ -0,0 +1,12 @@
# $NetBSD: Makefile,v 1.1 2008/05/14 16:49:48 reinoud Exp $
.include <bsd.own.mk>
WARNS= 4
PROG= mmcformat
MAN= mmcformat.8
SRCS= mmcformat.c uscsi_sense.c uscsi_subr.c
CPPFLAGS+= -DSCSI -DUSCSI_SCSIPI -I${NETBSDSRCDIR}/sys
.include <bsd.prog.mk>

43
usr.sbin/mmcformat/defs.h Normal file
View File

@ -0,0 +1,43 @@
/* $NetBSD: defs.h,v 1.1 2008/05/14 16:49:48 reinoud Exp $ */
/*
* File "defs.h" is part of the UDFclient toolkit.
* File $Id: defs.h,v 1.1 2008/05/14 16:49:48 reinoud Exp $ $Name: $
*
* Copyright (c) 2003, 2004, 2005, 2006 Reinoud Zandijk <reinoud@netbsd.org>
* All rights reserved.
*
* The UDFclient toolkit is distributed under the Clarified Artistic Licence.
* A copy of the licence is included in the distribution as
* `LICENCE.clearified.artistic' and a copy of the licence can also be
* requested at the GNU foundantion's website.
*
* Visit the UDFclient toolkit homepage http://www.13thmonkey.org/udftoolkit/
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef _DEFS_H_
#define _DEFS_H_
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <inttypes.h>
#endif /* _DEFS_H_ */

View File

@ -0,0 +1,136 @@
.\" $NetBSD: mmcformat.8,v 1.1 2008/05/14 16:49:48 reinoud Exp $
.\"
.\" Copyright (c) 2008 Reinoud Zandijk
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in
.\" the documentation and/or other materials provided with the
.\" distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
.\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY
.\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
.\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
.\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\"
.Dd May, 9, 2008
.Dt MMCFORMAT 8
.Os
.Sh NAME
.Nm mmcformat
.Nd format optical media
.Sh SYNOPSIS
.Nm
.Op Fl B
.Op Fl F
.Op Fl O
.Op Fl M
.Op Fl R
.Op Fl G
.Op Fl S
.Op Fl s
.Op Fl w
.Op Fl p
.Op Fl c Ar cert-num
.Op Fl r
.Op Fl h
.Op Fl H
.Op Fl I
.\" .Op X format is not implemented yet
.Op Fl b blockingnr
.Op D
.Ar special
.Sh DESCRIPTION
The
.Nm
utility formats optical media conforming to the MMC standard. These include
CD , DVD, and Blu-Ray (BD) media.
.Pp
The options are as follows:
.Bl -tag -width indent
.It Fl B
Blank media when possible before formatting it.
.It Fl F
Format media.
.It Fl O
Old style CD-RW formatting ; recommended for CD-RW.
.It Fl M
Select MRW (Mount Raineer) error correcting background format.
.It Fl R
Restart previously stopped MCD-MRW or DVD+RW backfround format.
.It Fl G
Grow last CD-RW/DVD-RW session.
.It Fl S
Grow spare space DVD-RAM / BD-RE.
.It Fl s
Format DVD+MRW / BD-RE with extra spare space.
.It Fl w
Wait until completion of background format.
.It Fl p
Explicitly set packet format.
.It Fl c Ar cert-num
Certify media for DVD-RAM / DV-RE. The argument cert-num specifies: 0) no
certification , 1) full certification , 2) quick certification.
.It Fl r
Recompile defect list for DVD-RAM.
.It Fl h
Show help or inquiry format possibilities for inserted media.
.It Fl H
Show help or inquiry format possibilities for inserted media.
.It Fl i
Show help or inquiry format possibilities for inserted media.
.It Fl b blockingnr
Explicit select packet size in sectors for CD-RW only; not recommended to
change from its default 32.
.It Fl D
Verbose all SCSI/ATAPI command errors.
.El
.Sh NOTES
Due to the enormous varieties in optical media, the tool is made as generic as
possible. This can result in confusion.
.Sh EXAMPLES
.Bd -literal -offset indent
mmcformat -B -O /dev/rcd0d
.Ed
.Pp
Blanks and then formats a CD-RW disc using the `old-style' format command. Its
recommended to use this `old-style' command unless your drive reports its not
supported; if so, resort to the default
.Fl F
.
Note that a CD-RW disc can be reformatted without being blanked. Blanking
swiches between sequential and fixed packet writing by erasing the disc. This
can also help to revive old discs.
.Pp
.Bd -literal -offset indent
mmcformat -F -M /dev/rcd0d
.Ed
.Pp
Format a CD-RW or a DVD+RW to use MRW (Mount Raineer). This format tries to
hide media flaws as much as possible by relocation.
.Sh SEE ALSO
.Xr scsictl 8
.Sh BUGS
It could be merged with
.Xr scsictl 8
but that tool is very harddisc oriented.
.Sh HISTORY
The
.Nm
command first appeared in
.Nx 5.0 .
.Sh AUTHORS
.An Reinoud Zandijk Aq reinoud@NetBSD.org .

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,829 @@
/* $NetBSD: uscsi_sense.c,v 1.1 2008/05/14 16:49:48 reinoud Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Charles M. Hannum.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Small changes made by Reinoud Zandijk <reinoud@netbsd.org>
*/
/*
* SCSI sense interpretation. Lifted from src/sys/dev/scsipi/scsipi_verbose.c,
* and modified for userland.
*/
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <inttypes.h>
#include "uscsilib.h"
static const char *sense_keys[16] = {
"No Additional Sense",
"Recovered Error",
"Not Ready",
"Media Error",
"Hardware Error",
"Illegal Request",
"Unit Attention",
"Write Protected",
"Blank Check",
"Vendor Unique",
"Copy Aborted",
"Aborted Command",
"Equal Error",
"Volume Overflow",
"Miscompare Error",
"Reserved"
};
/*
* The current version of this list can be obtained from
* <ftp://ftp.t10.org/t10/drafts/spc3/asc-num.txt>
*/
static const struct {
unsigned char asc;
unsigned char ascq;
const char *description;
} adesc[] = {
{ 0x00, 0x00, "No Additional Sense Information" },
{ 0x00, 0x01, "Filemark Detected" },
{ 0x00, 0x02, "End-Of-Partition/Medium Detected" },
{ 0x00, 0x03, "Setmark Detected" },
{ 0x00, 0x04, "Beginning-Of-Partition/Medium Detected" },
{ 0x00, 0x05, "End-Of-Data Detected" },
{ 0x00, 0x06, "I/O Process Terminated" },
{ 0x00, 0x11, "Audio Play Operation In Progress" },
{ 0x00, 0x12, "Audio Play Operation Paused" },
{ 0x00, 0x13, "Audio Play Operation Successfully Completed" },
{ 0x00, 0x14, "Audio Play Operation Stopped Due to Error" },
{ 0x00, 0x15, "No Current Audio Status To Return" },
{ 0x00, 0x16, "Operation In Progress" },
{ 0x00, 0x17, "Cleaning Requested" },
{ 0x00, 0x18, "Erase Operation In Progress" },
{ 0x00, 0x19, "Locate Operation In Progress" },
{ 0x00, 0x1A, "Rewind Operation In Progress" },
{ 0x00, 0x1B, "Set Capacity Operation In Progess" },
{ 0x00, 0x1C, "Verify Operation In Progress" },
{ 0x01, 0x00, "No Index/Sector Signal" },
{ 0x02, 0x00, "No Seek Complete" },
{ 0x03, 0x00, "Peripheral Device Write Fault" },
{ 0x03, 0x01, "No Write Current" },
{ 0x03, 0x02, "Excessive Write Errors" },
{ 0x04, 0x00, "Logical Unit Not Ready, Cause Not Reportable" },
{ 0x04, 0x01, "Logical Unit Is in Process Of Becoming Ready" },
{ 0x04, 0x02, "Logical Unit Not Ready, Initialization Command Required" },
{ 0x04, 0x03, "Logical Unit Not Ready, Manual Intervention Required" },
{ 0x04, 0x04, "Logical Unit Not Ready, Format In Progress" },
{ 0x04, 0x05, "Logical Unit Not Ready, Rebuild In Progress" },
{ 0x04, 0x06, "Logical Unit Not Ready, Recalculation In Progress" },
{ 0x04, 0x07, "Logical Unit Not Ready, Operation In Progress" },
{ 0x04, 0x08, "Logical Unit Not Ready, Long Write In Progress" },
{ 0x04, 0x09, "Logical Unit Not Ready, Self-Test In Progress" },
{ 0x04, 0x0A, "Logical Unit Not Accessible, Asymmetric Access State "
"Transition" },
{ 0x04, 0x0B, "Logical Unit Not Accessible, Target Port In Standby State" },
{ 0x04, 0x0C, "Logical Unit Not Accessible, Target Port In Unavailable State" },
{ 0x04, 0x10, "Logical Unit Not Ready, Auxiliary Memory Not Accessible" },
{ 0x04, 0x11, "Logical Unit Not Ready, Notify (Enable_Spinup) Required" },
{ 0x05, 0x00, "Logical Unit Does Not Respond To Selection" },
{ 0x06, 0x00, "No Reference Position Found" },
{ 0x07, 0x00, "Multiple Peripheral Devices Selected" },
{ 0x08, 0x00, "Logical Unit Communication Failure" },
{ 0x08, 0x01, "Logical Unit Communication Timeout" },
{ 0x08, 0x02, "Logical Unit Communication Parity Error" },
{ 0x08, 0x03, "Logical Unit Communication CRC Error" },
{ 0x08, 0x04, "Unreachable Copy Target" },
{ 0x09, 0x00, "Track Following Error" },
{ 0x09, 0x01, "Tracking Servo Failure" },
{ 0x09, 0x02, "Focus Servo Failure" },
{ 0x09, 0x03, "Spindle Servo Failure" },
{ 0x09, 0x04, "Head Select Fault" },
{ 0x0A, 0x00, "Error Log Overflow" },
{ 0x0B, 0x00, "Warning" },
{ 0x0B, 0x01, "Warning - Specified Temperature Exceeded" },
{ 0x0B, 0x02, "Warning - Enclosure Degraded" },
{ 0x0C, 0x00, "Write Error" },
{ 0x0C, 0x01, "Write Error - Recovered with Auto Reallocation" },
{ 0x0C, 0x02, "Write Error - Auto Reallocate Failed" },
{ 0x0C, 0x03, "Write Error - Recommend Reassignment" },
{ 0x0C, 0x04, "Compression Check Miscompare Error" },
{ 0x0C, 0x05, "Data Expansion Occurred During Compression" },
{ 0x0C, 0x06, "Block Not Compressible" },
{ 0x0C, 0x07, "Write Error - Recovery Needed" },
{ 0x0C, 0x08, "Write Error - Recovery Failed" },
{ 0x0C, 0x09, "Write Error - Loss Of Streaming" },
{ 0x0C, 0x0A, "Write Error - Padding Blocks Added" },
{ 0x0C, 0x0B, "Auxiliary Memory Write Error" },
{ 0x0C, 0x0C, "Write Error - Unexpected Unsolicited Data" },
{ 0x0C, 0x0D, "Write Error - Not Enough Unsolicited Data" },
{ 0x0D, 0x00, "Error Detected By Third Party Temporary Initiator" },
{ 0x0D, 0x01, "Third Party Device Failure" },
{ 0x0D, 0x02, "Copy Target Device Not Reachable" },
{ 0x0D, 0x03, "Incorrect Copy Target Device Type" },
{ 0x0D, 0x04, "Copy Target Device Data Underrun" },
{ 0x0D, 0x05, "Copy Target Device Data Overrun" },
{ 0x0E, 0x00, "Invalid Information Unit" },
{ 0x0E, 0x01, "Information Unit Too Short" },
{ 0x0E, 0x02, "Information Unit Too Long" },
{ 0x10, 0x00, "ID CRC Or ECC Error" },
{ 0x11, 0x00, "Unrecovered Read Error" },
{ 0x11, 0x01, "Read Retries Exhausted" },
{ 0x11, 0x02, "Error Too Long To Correct" },
{ 0x11, 0x03, "Multiple Read Errors" },
{ 0x11, 0x04, "Unrecovered Read Error - Auto Reallocate Failed" },
{ 0x11, 0x05, "L-EC Uncorrectable Error" },
{ 0x11, 0x06, "CIRC Unrecovered Error" },
{ 0x11, 0x07, "Data Re-synchronization Error" },
{ 0x11, 0x08, "Incomplete Block Read" },
{ 0x11, 0x09, "No Gap Found" },
{ 0x11, 0x0A, "Miscorrected Error" },
{ 0x11, 0x0B, "Uncorrected Read Error - Recommend Reassignment" },
{ 0x11, 0x0C, "Uncorrected Read Error - Recommend Rewrite the Data" },
{ 0x11, 0x0D, "De-Compression CRC Error" },
{ 0x11, 0x0E, "Cannot Decompress Using Declared Algorithm" },
{ 0x11, 0x0F, "Error Reading UPC/EAN Number" },
{ 0x11, 0x10, "Error Reading ISRC Number" },
{ 0x11, 0x11, "Read Error - Loss Of Streaming" },
{ 0x11, 0x12, "Auxiliary Memory Read Error" },
{ 0x11, 0x13, "Read Error - Failed Retransmission Request" },
{ 0x12, 0x00, "Address Mark Not Found for ID Field" },
{ 0x13, 0x00, "Address Mark Not Found for Data Field" },
{ 0x14, 0x00, "Recorded Entity Not Found" },
{ 0x14, 0x01, "Record Not Found" },
{ 0x14, 0x02, "Filemark or Setmark Not Found" },
{ 0x14, 0x03, "End-Of-Data Not Found" },
{ 0x14, 0x04, "Block Sequence Error" },
{ 0x14, 0x05, "Record Not Found - Recommend Reassignment" },
{ 0x14, 0x06, "Record Not Found - Data Auto-Reallocated" },
{ 0x14, 0x07, "Locate Operation Failure" },
{ 0x15, 0x00, "Random Positioning Error" },
{ 0x15, 0x01, "Mechanical Positioning Error" },
{ 0x15, 0x02, "Positioning Error Detected By Read of Medium" },
{ 0x16, 0x00, "Data Synchronization Mark Error" },
{ 0x16, 0x01, "Data Sync Error - Data Rewritten" },
{ 0x16, 0x02, "Data Sync Error - Recommend Rewrite" },
{ 0x16, 0x03, "Data Sync Error - Data Auto-Reallocated" },
{ 0x16, 0x04, "Data Sync Error - Recommend Reassignment" },
{ 0x17, 0x00, "Recovered Data With No Error Correction Applied" },
{ 0x17, 0x01, "Recovered Data With Retries" },
{ 0x17, 0x02, "Recovered Data With Positive Head Offset" },
{ 0x17, 0x03, "Recovered Data With Negative Head Offset" },
{ 0x17, 0x04, "Recovered Data With Retries and/or CIRC Applied" },
{ 0x17, 0x05, "Recovered Data Using Previous Sector ID" },
{ 0x17, 0x06, "Recovered Data Without ECC - Data Auto-Reallocated" },
{ 0x17, 0x07, "Recovered Data Without ECC - Recommend Reassignment" },
{ 0x17, 0x08, "Recovered Data Without ECC - Recommend Rewrite" },
{ 0x17, 0x09, "Recovered Data Without ECC - Data Rewritten" },
{ 0x18, 0x00, "Recovered Data With Error Correction Applied" },
{ 0x18, 0x01, "Recovered Data With Error Correction & Retries Applied" },
{ 0x18, 0x02, "Recovered Data - Data Auto-Reallocated" },
{ 0x18, 0x03, "Recovered Data With CIRC" },
{ 0x18, 0x04, "Recovered Data With LEC" },
{ 0x18, 0x05, "Recovered Data - Recommend Reassignment" },
{ 0x18, 0x06, "Recovered Data - Recommend Rewrite" },
{ 0x18, 0x07, "Recovered Data With ECC - Data Rewritten" },
{ 0x18, 0x08, "Recovered Data With Linking" },
{ 0x19, 0x00, "Defect List Error" },
{ 0x19, 0x01, "Defect List Not Available" },
{ 0x19, 0x02, "Defect List Error in Primary List" },
{ 0x19, 0x03, "Defect List Error in Grown List" },
{ 0x1A, 0x00, "Parameter List Length Error" },
{ 0x1B, 0x00, "Synchronous Data Transfer Error" },
{ 0x1C, 0x00, "Defect List Not Found" },
{ 0x1C, 0x01, "Primary Defect List Not Found" },
{ 0x1C, 0x02, "Grown Defect List Not Found" },
{ 0x1D, 0x00, "Miscompare During Verify Operation" },
{ 0x1E, 0x00, "Recovered ID with ECC Correction" },
{ 0x1F, 0x00, "Partial Defect List Transfer" },
{ 0x20, 0x00, "Invalid Command Operation Code" },
{ 0x20, 0x01, "Access Denied - Initiator Pending-Enrolled" },
{ 0x20, 0x02, "Access Denied - No Access Rights" },
{ 0x20, 0x03, "Access Denied - Invalid Mgmt ID Key" },
{ 0x20, 0x04, "Illegal Command While In Write Capable State" },
{ 0x20, 0x06, "Illegal Command While In Explicit Address Mode" },
{ 0x20, 0x07, "Illegal Command While In Implicit Address Mode" },
{ 0x20, 0x08, "Access Denied - Enrollment Conflict" },
{ 0x20, 0x09, "Access Denied - Invalid LU Identifer" },
{ 0x20, 0x0A, "Access Denied - Invalid Proxy Token" },
{ 0x20, 0x0B, "Access Denied - ACL LUN Conflict" },
{ 0x21, 0x00, "Logical Block Address Out of Range" },
{ 0x21, 0x01, "Invalid Element Address" },
{ 0x21, 0x02, "Invalid Address For Write" },
{ 0x22, 0x00, "Illegal Function (Use 20 00, 24 00, or 26 00)" },
{ 0x24, 0x00, "Illegal Field in CDB" },
{ 0x24, 0x01, "CDB Decryption Error" },
{ 0x24, 0x04, "Security Audit Value Frozen" },
{ 0x24, 0x05, "Security Working Key Frozen" },
{ 0x24, 0x06, "Nonce Not Unique" },
{ 0x24, 0x07, "Nonce Timestamp Out Of Range" },
{ 0x25, 0x00, "Logical Unit Not Supported" },
{ 0x26, 0x00, "Invalid Field In Parameter List" },
{ 0x26, 0x01, "Parameter Not Supported" },
{ 0x26, 0x02, "Parameter Value Invalid" },
{ 0x26, 0x03, "Threshold Parameters Not Supported" },
{ 0x26, 0x04, "Invalid Release Of Persistent Reservation" },
{ 0x26, 0x05, "Data Decryption Error" },
{ 0x26, 0x06, "Too Many Target Descriptors" },
{ 0x26, 0x07, "Unsupported Target Descriptor Type Code" },
{ 0x26, 0x08, "Too Many Segment Descriptors" },
{ 0x26, 0x09, "Unsupported Segment Descriptor Type Code" },
{ 0x26, 0x0A, "Unexpected Inexact Segment" },
{ 0x26, 0x0B, "Inline Data Length Exceeded" },
{ 0x26, 0x0C, "Invalid Operation For Copy Source Or Destination" },
{ 0x26, 0x0D, "Copy Segment Granularity Violation" },
{ 0x26, 0x0E, "Invalid Parameter While Port Is Enabled" },
{ 0x27, 0x00, "Write Protected" },
{ 0x27, 0x01, "Hardware Write Protected" },
{ 0x27, 0x02, "Logical Unit Software Write Protected" },
{ 0x27, 0x03, "Associated Write Protect" },
{ 0x27, 0x04, "Persistent Write Protect" },
{ 0x27, 0x05, "Permanent Write Protect" },
{ 0x27, 0x06, "Conditional Write Protect" },
{ 0x28, 0x00, "Not Ready To Ready Transition (Medium May Have Changed)" },
{ 0x28, 0x01, "Import Or Export Element Accessed" },
{ 0x29, 0x00, "Power On, Reset, or Bus Device Reset Occurred" },
{ 0x29, 0x01, "Power On Occurred" },
{ 0x29, 0x02, "SCSI Bus Reset Occurred" },
{ 0x29, 0x03, "Bus Device Reset Function Occurred" },
{ 0x29, 0x04, "Device Internal Reset" },
{ 0x29, 0x05, "Transceiver Mode Changed To Single-Ended" },
{ 0x29, 0x06, "Transceiver Mode Changed To LVD" },
{ 0x29, 0x07, "I_T Nexus Loss Occurred" },
{ 0x2A, 0x00, "Parameters Changed" },
{ 0x2A, 0x01, "Mode Parameters Changed" },
{ 0x2A, 0x02, "Log Parameters Changed" },
{ 0x2A, 0x03, "Reservations Preempted" },
{ 0x2A, 0x04, "Reservations Released" },
{ 0x2A, 0x05, "Registrations Preempted" },
{ 0x2A, 0x06, "Asymmetric Access State Changed" },
{ 0x2A, 0x07, "Implicit Asymmetric Access State Transition Failed" },
{ 0x2B, 0x00, "Copy Cannot Execute Since Host Cannot Disconnect" },
{ 0x2C, 0x00, "Command Sequence Error" },
{ 0x2C, 0x01, "Too Many Windows Specified" },
{ 0x2C, 0x02, "Invalid Combination of Windows Specified" },
{ 0x2C, 0x03, "Current Program Area Is Not Empty" },
{ 0x2C, 0x04, "Current Program Area Is Empty" },
{ 0x2C, 0x05, "Illegal Power Condition Request" },
{ 0x2C, 0x06, "Persistent Prevent Conflict" },
{ 0x2C, 0x07, "Previous Busy Status" },
{ 0x2C, 0x08, "Previous Task Set Full Status" },
{ 0x2C, 0x09, "Previous Reservation Conflict Status" },
{ 0x2C, 0x0A, "Partition or Collection Contains User Objects" },
{ 0x2D, 0x00, "Overwrite Error On Update In Place" },
{ 0x2E, 0x00, "Insufficient Time For Operation" },
{ 0x2F, 0x00, "Commands Cleared By Another Initiator" },
{ 0x30, 0x00, "Incompatible Medium Installed" },
{ 0x30, 0x01, "Cannot Read Medium - Unknown Format" },
{ 0x30, 0x02, "Cannot Read Medium - Incompatible Format" },
{ 0x30, 0x03, "Cleaning Cartridge Installed" },
{ 0x30, 0x04, "Cannot Write Medium - Unknown Format" },
{ 0x30, 0x05, "Cannot Write Medium - Incompatible Format" },
{ 0x30, 0x06, "Cannot Format Medium - Incompatible Medium" },
{ 0x30, 0x07, "Cleaning Failure" },
{ 0x30, 0x08, "Cannot Write - Application Code Mismatch" },
{ 0x30, 0x09, "Current Session Not Fixated For Append" },
{ 0x30, 0x0A, "Cleaning Request Rejected" },
{ 0x30, 0x10, "Medium Not Formatted" },
{ 0x31, 0x00, "Medium Format Corrupted" },
{ 0x31, 0x01, "Format Command Failed" },
{ 0x31, 0x02, "Zoned Formatting Failed Due To Spare Linking" },
{ 0x32, 0x00, "No Defect Spare Location Available" },
{ 0x32, 0x01, "Defect List Update Failure" },
{ 0x33, 0x00, "Tape Length Error" },
{ 0x34, 0x00, "Enclosure Failure" },
{ 0x35, 0x00, "Enclosure Services Failure" },
{ 0x35, 0x01, "Unsupported Enclosure Function" },
{ 0x35, 0x02, "Enclosure Services Unavailable" },
{ 0x35, 0x03, "Enclosure Services Transfer Failed" },
{ 0x35, 0x04, "Enclosure Services Transfer Refused" },
{ 0x36, 0x00, "Ribbon, Ink, or Toner Failure" },
{ 0x37, 0x00, "Rounded Parameter" },
{ 0x39, 0x00, "Saving Parameters Not Supported" },
{ 0x3A, 0x00, "Medium Not Present" },
{ 0x3A, 0x01, "Medium Not Present - Tray Closed" },
{ 0x3A, 0x02, "Medium Not Present - Tray Open" },
{ 0x3A, 0x03, "Medium Not Present - Loadable" },
{ 0x3A, 0x04, "Medium Not Present - Medium Auxilliary Memory Accessible" },
{ 0x3B, 0x00, "Sequential Positioning Error" },
{ 0x3B, 0x01, "Tape Position Error At Beginning-of-Medium" },
{ 0x3B, 0x02, "Tape Position Error At End-of-Medium" },
{ 0x3B, 0x03, "Tape or Electronic Vertical Forms Unit Not Ready" },
{ 0x3B, 0x04, "Slew Failure" },
{ 0x3B, 0x05, "Paper Jam" },
{ 0x3B, 0x06, "Failed To Sense Top-Of-Form" },
{ 0x3B, 0x07, "Failed To Sense Bottom-Of-Form" },
{ 0x3B, 0x08, "Reposition Error" },
{ 0x3B, 0x09, "Read Past End Of Medium" },
{ 0x3B, 0x0A, "Read Past Begining Of Medium" },
{ 0x3B, 0x0B, "Position Past End Of Medium" },
{ 0x3B, 0x0C, "Position Past Beginning Of Medium" },
{ 0x3B, 0x0D, "Medium Destination Element Full" },
{ 0x3B, 0x0E, "Medium Source Element Empty" },
{ 0x3B, 0x0F, "End Of Medium Reached" },
{ 0x3B, 0x11, "Medium Magazine Not Accessible" },
{ 0x3B, 0x12, "Medium Magazine Removed" },
{ 0x3B, 0x13, "Medium Magazine Inserted" },
{ 0x3B, 0x14, "Medium Magazine Locked" },
{ 0x3B, 0x15, "Medium Magazine Unlocked" },
{ 0x3B, 0x16, "Mechanical Positioning Or Changer Error" },
{ 0x3D, 0x00, "Invalid Bits In IDENTIFY Message" },
{ 0x3E, 0x00, "Logical Unit Has Not Self-Configured Yet" },
{ 0x3E, 0x01, "Logical Unit Failure" },
{ 0x3E, 0x02, "Timeout On Logical Unit" },
{ 0x3E, 0x03, "Logical Unit Failed Self-Test" },
{ 0x3E, 0x04, "Logical Unit Unable To Update Self-Test Log" },
{ 0x3F, 0x00, "Target Operating Conditions Have Changed" },
{ 0x3F, 0x01, "Microcode Has Been Changed" },
{ 0x3F, 0x02, "Changed Operating Definition" },
{ 0x3F, 0x03, "INQUIRY Data Has Changed" },
{ 0x3F, 0x04, "Component Device Attached" },
{ 0x3F, 0x05, "Device Identifier Changed" },
{ 0x3F, 0x06, "Redundancy Group Created Or Modified" },
{ 0x3F, 0x07, "Redundancy Group Deleted" },
{ 0x3F, 0x08, "Spare Created Or Modified" },
{ 0x3F, 0x09, "Spare Deleted" },
{ 0x3F, 0x0A, "Volume Set Created Or Modified" },
{ 0x3F, 0x0B, "Volume Set Deleted" },
{ 0x3F, 0x0C, "Volume Set Deassigned" },
{ 0x3F, 0x0D, "Volume Set Reassigned" },
{ 0x3F, 0x0E, "Reported LUNs Data Has Changed" },
{ 0x3F, 0x0F, "Echo Buffer Overwritten" },
{ 0x3F, 0x10, "Medium Loadable" },
{ 0x3F, 0x11, "Medium Auxiliary Memory Accessible" },
{ 0x40, 0x00, "RAM FAILURE (Should Use 40 NN)" },
{ 0x41, 0x00, "Data Path FAILURE (Should Use 40 NN)" },
{ 0x42, 0x00, "Power-On or Self-Test FAILURE (Should Use 40 NN)" },
{ 0x43, 0x00, "Message Error" },
{ 0x44, 0x00, "Internal Target Failure" },
{ 0x45, 0x00, "Select Or Reselect Failure" },
{ 0x46, 0x00, "Unsuccessful Soft Reset" },
{ 0x47, 0x00, "SCSI Parity Error" },
{ 0x47, 0x01, "Data Phase CRC Error Detected" },
{ 0x47, 0x02, "SCSI Parity Error Detected During ST Data Phase" },
{ 0x47, 0x03, "Information Unit iuCRC Error Detected" },
{ 0x47, 0x04, "Asynchronous Information Protection Error Detected" },
{ 0x47, 0x05, "Protocol Service CRC Error" },
{ 0x47, 0x7F, "Some Commands Cleared by iSCSI Protocol Event" },
{ 0x48, 0x00, "INITIATOR DETECTED ERROR Message Received" },
{ 0x49, 0x00, "Invalid Message Error" },
{ 0x4A, 0x00, "Command Phase Error" },
{ 0x4B, 0x00, "Data Phase Error" },
{ 0x4B, 0x01, "Illegal Target Port Transfer Tag Received" },
{ 0x4B, 0x02, "Too Much Write Data" },
{ 0x4B, 0x03, "ACK/NAK Timeout" },
{ 0x4B, 0x04, "NAK Reveived" },
{ 0x4B, 0x05, "Data Offset Error" },
{ 0x4B, 0x06, "Initiator Response Timeout" },
{ 0x4C, 0x00, "Logical Unit Failed Self-Configuration" },
{ 0x4D, 0x00, "Tagged Overlapped Commands (NN = Queue Tag)" },
{ 0x4E, 0x00, "Overlapped Commands Attempted" },
{ 0x50, 0x00, "Write Append Error" },
{ 0x50, 0x01, "Write Append Position Error" },
{ 0x50, 0x02, "Position Error Related To Timing" },
{ 0x51, 0x00, "Erase Failure" },
{ 0x51, 0x01, "Erase Failure - Incomplete Erase Operation Detected" },
{ 0x52, 0x00, "Cartridge Fault" },
{ 0x53, 0x00, "Media Load or Eject Failed" },
{ 0x53, 0x01, "Unload Tape Failure" },
{ 0x53, 0x02, "Medium Removal Prevented" },
{ 0x54, 0x00, "SCSI To Host System Interface Failure" },
{ 0x55, 0x00, "System Resource Failure" },
{ 0x55, 0x01, "System Buffer Full" },
{ 0x55, 0x02, "Insufficient Reservation Resources" },
{ 0x55, 0x03, "Insufficient Resources" },
{ 0x55, 0x04, "Insufficient Registration Resources" },
{ 0x55, 0x05, "Insufficient Access Control Resources" },
{ 0x55, 0x06, "Auxiliary Memory Out Of Space" },
{ 0x57, 0x00, "Unable To Recover Table-Of-Contents" },
{ 0x58, 0x00, "Generation Does Not Exist" },
{ 0x59, 0x00, "Updated Block Read" },
{ 0x5A, 0x00, "Operator Request or State Change Input (Unspecified)" },
{ 0x5A, 0x01, "Operator Medium Removal Requested" },
{ 0x5A, 0x02, "Operator Selected Write Protect" },
{ 0x5A, 0x03, "Operator Selected Write Permit" },
{ 0x5B, 0x00, "Log Exception" },
{ 0x5B, 0x01, "Threshold Condition Met" },
{ 0x5B, 0x02, "Log Counter At Maximum" },
{ 0x5B, 0x03, "Log List Codes Exhausted" },
{ 0x5C, 0x00, "RPL Status Change" },
{ 0x5C, 0x01, "Spindles Synchronized" },
{ 0x5C, 0x02, "Spindles Not Synchronized" },
{ 0x5D, 0x00, "Failure Prediction Threshold Exceeded" },
{ 0x5D, 0x01, "Media Failure Prediction Threshold Exceeded" },
{ 0x5D, 0x02, "Logical Unit Failure Prediction Threshold Exceeded" },
{ 0x5D, 0x03, "Spare Area Exhaustion Prediction Threshold Exceeded" },
{ 0x5D, 0x10, "Hardware Impending Failure General Hard Drive Failure" },
{ 0x5D, 0x11, "Hardware Impending Failure Drive Error Rate Too High" },
{ 0x5D, 0x12, "Hardware Impending Failure Data Error Rate Too High" },
{ 0x5D, 0x13, "Hardware Impending Failure Seek Error Rate Too High" },
{ 0x5D, 0x14, "Hardware Impending Failure Too Many Block Reassigns" },
{ 0x5D, 0x15, "Hardware Impending Failure Access Times Too High" },
{ 0x5D, 0x16, "Hardware Impending Failure Start Unit Times Too High" },
{ 0x5D, 0x17, "Hardware Impending Failure Channel Parametrics" },
{ 0x5D, 0x18, "Hardware Impending Failure Controller Detected" },
{ 0x5D, 0x19, "Hardware Impending Failure Throughput Performance" },
{ 0x5D, 0x1A, "Hardware Impending Failure Seek Time Performance" },
{ 0x5D, 0x1B, "Hardware Impending Failure Spin-Up Retry Count" },
{ 0x5D, 0x1C, "Hardware Impending Failure Drive Calibration Retry Count" },
{ 0x5D, 0x20, "Controller Impending Failure General Hard Drive Failure" },
{ 0x5D, 0x21, "Controller Impending Failure Drive Error Rate Too High" },
{ 0x5D, 0x22, "Controller Impending Failure Data Error Rate Too High" },
{ 0x5D, 0x23, "Controller Impending Failure Seek Error Rate Too High" },
{ 0x5D, 0x24, "Controller Impending Failure Too Many Block Reassigns" },
{ 0x5D, 0x25, "Controller Impending Failure Access Times Too High" },
{ 0x5D, 0x26, "Controller Impending Failure Start Unit Times Too High" },
{ 0x5D, 0x27, "Controller Impending Failure Channel Parametrics" },
{ 0x5D, 0x28, "Controller Impending Failure Controller Detected" },
{ 0x5D, 0x29, "Controller Impending Failure Throughput Performance" },
{ 0x5D, 0x2A, "Controller Impending Failure Seek Time Performance" },
{ 0x5D, 0x2B, "Controller Impending Failure Spin-Up Retry Count" },
{ 0x5D, 0x2C, "Controller Impending Failure Drive Calibration Retry Count" },
{ 0x5D, 0x30, "Data Channel Impending Failure General Hard Drive Failure" },
{ 0x5D, 0x31, "Data Channel Impending Failure Drive Error Rate Too High" },
{ 0x5D, 0x32, "Data Channel Impending Failure Data Error Rate Too High" },
{ 0x5D, 0x33, "Data Channel Impending Failure Seek Error Rate Too High" },
{ 0x5D, 0x34, "Data Channel Impending Failure Too Many Block Reassigns" },
{ 0x5D, 0x35, "Data Channel Impending Failure Access Times Too High" },
{ 0x5D, 0x36, "Data Channel Impending Failure Start Unit Times Too High" },
{ 0x5D, 0x37, "Data Channel Impending Failure Channel Parametrics" },
{ 0x5D, 0x38, "Data Channel Impending Failure Controller Detected" },
{ 0x5D, 0x39, "Data Channel Impending Failure Throughput Performance" },
{ 0x5D, 0x3A, "Data Channel Impending Failure Seek Time Performance" },
{ 0x5D, 0x3B, "Data Channel Impending Failure Spin-Up Retry Count" },
{ 0x5D, 0x3C, "Data Channel Impending Failure Drive Calibration Retry Count" },
{ 0x5D, 0x40, "Servo Impending Failure General Hard Drive Failure" },
{ 0x5D, 0x41, "Servo Impending Failure Drive Error Rate Too High" },
{ 0x5D, 0x42, "Servo Impending Failure Data Error Rate Too High" },
{ 0x5D, 0x43, "Servo Impending Failure Seek Error Rate Too High" },
{ 0x5D, 0x44, "Servo Impending Failure Too Many Block Reassigns" },
{ 0x5D, 0x45, "Servo Impending Failure Access Times Too High" },
{ 0x5D, 0x46, "Servo Impending Failure Start Unit Times Too High" },
{ 0x5D, 0x47, "Servo Impending Failure Channel Parametrics" },
{ 0x5D, 0x48, "Servo Impending Failure Controller Detected" },
{ 0x5D, 0x49, "Servo Impending Failure Throughput Performance" },
{ 0x5D, 0x4A, "Servo Impending Failure Seek Time Performance" },
{ 0x5D, 0x4B, "Servo Impending Failure Spin-Up Retry Count" },
{ 0x5D, 0x4C, "Servo Impending Failure Drive Calibration Retry Count" },
{ 0x5D, 0x50, "Spindle Impending Failure General Hard Drive Failure" },
{ 0x5D, 0x51, "Spindle Impending Failure Drive Error Rate Too High" },
{ 0x5D, 0x52, "Spindle Impending Failure Data Error Rate Too High" },
{ 0x5D, 0x53, "Spindle Impending Failure Seek Error Rate Too High" },
{ 0x5D, 0x54, "Spindle Impending Failure Too Many Block Reassigns" },
{ 0x5D, 0x55, "Spindle Impending Failure Access Times Too High" },
{ 0x5D, 0x56, "Spindle Impending Failure Start Unit Times Too High" },
{ 0x5D, 0x57, "Spindle Impending Failure Channel Parametrics" },
{ 0x5D, 0x58, "Spindle Impending Failure Controller Detected" },
{ 0x5D, 0x59, "Spindle Impending Failure Throughput Performance" },
{ 0x5D, 0x5A, "Spindle Impending Failure Seek Time Performance" },
{ 0x5D, 0x5B, "Spindle Impending Failure Spin-Up Retry Count" },
{ 0x5D, 0x5C, "Spindle Impending Failure Drive Calibration Retry Count" },
{ 0x5D, 0x60, "Firmware Impending Failure General Hard Drive Failure" },
{ 0x5D, 0x61, "Firmware Impending Failure Drive Error Rate Too High" },
{ 0x5D, 0x62, "Firmware Impending Failure Data Error Rate Too High" },
{ 0x5D, 0x63, "Firmware Impending Failure Seek Error Rate Too High" },
{ 0x5D, 0x64, "Firmware Impending Failure Too Many Block Reassigns" },
{ 0x5D, 0x65, "Firmware Impending Failure Access Times Too High" },
{ 0x5D, 0x66, "Firmware Impending Failure Start Unit Times Too High" },
{ 0x5D, 0x67, "Firmware Impending Failure Channel Parametrics" },
{ 0x5D, 0x68, "Firmware Impending Failure Controller Detected" },
{ 0x5D, 0x69, "Firmware Impending Failure Throughput Performance" },
{ 0x5D, 0x6A, "Firmware Impending Failure Seek Time Performance" },
{ 0x5D, 0x6B, "Firmware Impending Failure Spin-Up Retry Count" },
{ 0x5D, 0x6C, "Firmware Impending Failure Drive Calibration Retry Count" },
{ 0x5D, 0xFF, "Failure Prediction Threshold Exceeded (False)" },
{ 0x5E, 0x00, "Low Power Condition On" },
{ 0x5E, 0x01, "Idle Condition Activated By Timer" },
{ 0x5E, 0x02, "Standby Condition Activated By Timer" },
{ 0x5E, 0x03, "Idle Condition Activated By Command" },
{ 0x5E, 0x04, "Standby Condition Activated By Command" },
{ 0x5E, 0x41, "Power State Change To Active" },
{ 0x5E, 0x42, "Power State Change To Idle" },
{ 0x5E, 0x43, "Power State Change To Standby" },
{ 0x5E, 0x45, "Power State Change To Sleep" },
{ 0x5E, 0x47, "Power State Change To Device Control" },
{ 0x60, 0x00, "Lamp Failure" },
{ 0x61, 0x00, "Video Acquisition Error" },
{ 0x61, 0x01, "Unable To Acquire Video" },
{ 0x61, 0x02, "Out Of Focus" },
{ 0x62, 0x00, "Scan Head Positioning Error" },
{ 0x63, 0x00, "End Of User Area Encountered On This Track" },
{ 0x63, 0x01, "Packet Does Not Fit In Available Space" },
{ 0x64, 0x00, "Illegal Mode For This Track" },
{ 0x64, 0x01, "Invalid Packet Size" },
{ 0x65, 0x00, "Voltage Fault" },
{ 0x66, 0x00, "Automatic Document Feeder Cover Up" },
{ 0x66, 0x01, "Automatic Document Feeder Lift Up" },
{ 0x66, 0x02, "Document Jam In Automatic Document Feeder" },
{ 0x66, 0x03, "Document Misfeed In Automatic Document Feeder" },
{ 0x67, 0x00, "Configuration Failure" },
{ 0x67, 0x01, "Configuration Of Incapable Logical Units Failed" },
{ 0x67, 0x02, "Add Logical Unit Failed" },
{ 0x67, 0x03, "Modification Of Logical Unit Failed" },
{ 0x67, 0x04, "Exchange Of Logical Unit Failed" },
{ 0x67, 0x05, "Remove Of Logical Unit Failed" },
{ 0x67, 0x06, "Attachment Of Logical Unit Failed" },
{ 0x67, 0x07, "Creation of Logical Unit Failed" },
{ 0x67, 0x08, "Assign Failure Occurred" },
{ 0x67, 0x09, "Multiply Assigned Logical Unit" },
{ 0x67, 0x0A, "Set Target Port Groups Command Failed" },
{ 0x68, 0x00, "Logical Unit Not Configured" },
{ 0x69, 0x00, "Data Loss On Logical Unit" },
{ 0x69, 0x01, "Multiple Logical Unit Failures" },
{ 0x69, 0x02, "Parity/Data Mismatch" },
{ 0x6A, 0x00, "Informational, Refer To Log" },
{ 0x6B, 0x00, "State Change Has Occurred" },
{ 0x6B, 0x01, "Redundancy Level Got Better" },
{ 0x6B, 0x02, "Redundancy Level Got Worse" },
{ 0x6C, 0x00, "Rebuild Failure Occurred" },
{ 0x6D, 0x00, "Recalculate Failure Occurred" },
{ 0x6E, 0x00, "Command To Logical Unit Failed" },
{ 0x6F, 0x00, "Copy Protection Key Exchange Failure - Authentication Failure" },
{ 0x6F, 0x01, "Copy Protection Key Exchange Failure - Key Not Present" },
{ 0x6F, 0x02, "Copy Protection Key Exchange Failure - Key Not Established" },
{ 0x6F, 0x03, "Read Of Scrambled Sector Without Authentication" },
{ 0x6F, 0x04, "Media Region Code Is Mismatched To Logical Unit Region" },
{ 0x6F, 0x05, "Drive Region Must Be Permanent/Region Reset Count Error" },
{ 0x70, 0x00, "Decompression Exception Short Algorithm ID Of NN" },
{ 0x71, 0x00, "Decompression Exception Long Algorithm ID" },
{ 0x72, 0x00, "Session Fixation Error" },
{ 0x72, 0x01, "Session Fixation Error Writing Lead-In" },
{ 0x72, 0x02, "Session Fixation Error Writing Lead-Out" },
{ 0x72, 0x03, "Session Fixation Error - Incomplete Track In Session" },
{ 0x72, 0x04, "Empty Or Partially Written Reserved Track" },
{ 0x72, 0x05, "No More Track Reservations Allowed" },
{ 0x73, 0x00, "CD Control Error" },
{ 0x73, 0x01, "Power Calibration Area Almost Full" },
{ 0x73, 0x02, "Power Calibration Area Is Full" },
{ 0x73, 0x03, "Power Calibration Area Error" },
{ 0x73, 0x04, "Program Memory Area Update Failure" },
{ 0x73, 0x05, "Program Memory Area Is Full" },
{ 0x73, 0x06, "RMA/PMA Is Almost Full" },
{ 0x00, 0x00, NULL }
};
/* needs to move to a compat.c one day */
#ifdef NO_STRLCPY
size_t
strlcpy(char *dst, const char *src, size_t size)
{
strncpy(dst, src, size-1);
dst[size] = '\0';
return strlen(src);
}
#endif
static void
asc2ascii(u_char asc, u_char ascq, char *result, size_t l)
{
int i = 0;
while (adesc[i].description != NULL) {
if (adesc[i].asc == asc && adesc[i].ascq == ascq)
break;
i++;
}
if (adesc[i].description == NULL) {
if (asc == 0x40 && ascq != 0)
(void) snprintf(result, l,
"Diagnostic Failure on Component 0x%02x",
ascq & 0xff);
else
(void) snprintf(result, l, "ASC 0x%02x ASCQ 0x%02x",
asc & 0xff, ascq & 0xff);
} else
(void) strlcpy(result, adesc[i].description, l);
}
static void
uscsi_print_sense_data(uint8_t *s, int slen, int verbosity)
{
int32_t info;
int i, j, k;
char *sbs;
/*
* Basics - print out SENSE KEY
*/
printf(" SENSE KEY: %s", uscsi_decode_sense(s, 0));
/*
* Print out, unqualified but aligned, FMK, EOM and ILI status.
*/
if (s[2] & 0xe0) {
char pad;
printf("\n ");
pad = ' ';
if (s[2] & SSD_FILEMARK) {
printf("%c Filemark Detected", pad);
pad = ',';
}
if (s[2] & SSD_EOM) {
printf("%c EOM Detected", pad);
pad = ',';
}
if (s[2] & SSD_ILI)
printf("%c Incorrect Length Indicator Set", pad);
}
/*
* Now we should figure out, based upon device type, how
* to format the information field. Unfortunately, that's
* not convenient here, so we'll print it as a signed
* 32 bit integer.
*/
//info = _4btol(&s[3]);
info = (s[3] << 24) | (s[4] << 16) | (s[5] << 8) | s[6];
if (info)
printf("\n INFO FIELD: %d", info);
/*
* Now we check additional length to see whether there is
* more information to extract.
*/
/* enough for command specific information? */
if (((unsigned int) s[7]) < 4) {
printf("\n");
return;
}
// info = _4btol(&s[8]);
info = (s[8] << 24) | (s[9] << 16) | (s[10] << 8) | s[11];
if (info)
printf("\n COMMAND INFO: %d (0x%x)", info, info);
/*
* Decode ASC && ASCQ info, plus FRU, plus the rest...
*/
sbs = uscsi_decode_sense(s, 1);
if (sbs)
printf("\n ASC/ASCQ: %s", sbs);
if (s[14] != 0)
printf("\n FRU CODE: 0x%x", s[14] & 0xff);
sbs = uscsi_decode_sense(s, 3);
if (sbs)
printf("\n SKSV: %s", sbs);
printf("\n");
if (verbosity == 0) {
printf("\n");
return;
}
/*
* Now figure whether we should print any additional informtion.
*
* Where should we start from? If we had SKSV data,
* start from offset 18, else from offset 15.
*
* From that point until the end of the buffer, check for any
* nonzero data. If we have some, go back and print the lot,
* otherwise we're done.
*/
if (sbs)
i = 18;
else
i = 15;
for (j = i; j < slen; j++)
if (s[j])
break;
if (j == slen)
return;
printf("\n Additional Sense Information (byte %d out...):\n", i);
if (i == 15) {
printf("\n\t%2d:", i);
k = 7;
} else {
printf("\n\t%2d:", i);
k = 2;
j -= 2;
}
while (j > 0) {
if (i >= slen)
break;
if (k == 8) {
k = 0;
printf("\n\t%2d:", i);
}
printf(" 0x%02x", s[i] & 0xff);
k++;
j--;
i++;
}
printf("\n\n");
}
char *
uscsi_decode_sense(void *sinfo, int flag)
{
unsigned char *snsbuf;
unsigned char skey;
static char rqsbuf[132];
skey = 0;
snsbuf = (unsigned char *) sinfo;
if (flag == 0 || flag == 2 || flag == 3)
skey = snsbuf[2] & 0xf;
if (flag == 0) { /* Sense Key Only */
(void) strlcpy(rqsbuf, sense_keys[skey], sizeof(rqsbuf));
return (rqsbuf);
} else if (flag == 1) { /* ASC/ASCQ Only */
asc2ascii(snsbuf[12], snsbuf[13], rqsbuf, sizeof(rqsbuf));
return (rqsbuf);
} else if (flag == 2) { /* Sense Key && ASC/ASCQ */
auto char localbuf[64];
asc2ascii(snsbuf[12], snsbuf[13], localbuf, sizeof(localbuf));
(void) snprintf(rqsbuf, sizeof(rqsbuf), "%s, %s",
sense_keys[skey], localbuf);
return (rqsbuf);
} else if (flag == 3 && snsbuf[7] >= 9 && (snsbuf[15] & 0x80)) {
/*
* SKSV Data
*/
switch (skey) {
case SKEY_ILLEGAL_REQUEST:
if (snsbuf[15] & 0x8)
(void)snprintf(rqsbuf, sizeof(rqsbuf),
"Error in %s, Offset %d, bit %d",
(snsbuf[15] & 0x40)? "CDB" : "Parameters",
(snsbuf[16] & 0xff) << 8 |
(snsbuf[17] & 0xff), snsbuf[15] & 0x7);
else
(void)snprintf(rqsbuf, sizeof(rqsbuf),
"Error in %s, Offset %d",
(snsbuf[15] & 0x40)? "CDB" : "Parameters",
(snsbuf[16] & 0xff) << 8 |
(snsbuf[17] & 0xff));
return (rqsbuf);
case SKEY_RECOVERED_ERROR:
case SKEY_MEDIUM_ERROR:
case SKEY_HARDWARE_ERROR:
(void)snprintf(rqsbuf, sizeof(rqsbuf),
"Actual Retry Count: %d",
(snsbuf[16] & 0xff) << 8 | (snsbuf[17] & 0xff));
return (rqsbuf);
case SKEY_NOT_READY:
(void)snprintf(rqsbuf, sizeof(rqsbuf),
"Progress Indicator: %d",
(snsbuf[16] & 0xff) << 8 | (snsbuf[17] & 0xff));
return (rqsbuf);
default:
break;
}
}
return (NULL);
}
void
uscsi_print_sense(const char *name, u_char *req_cmd, int req_cmdlen,
u_char *req_sense, int req_senselen_used, int verbosity)
{
int i;
printf("%s: Check Condition on CDB:", name);
for (i = 0; i < req_cmdlen; i++)
printf(" %02x", req_cmd[i]);
printf("\n");
uscsi_print_sense_data(req_sense, req_senselen_used, verbosity);
}

View File

@ -0,0 +1,580 @@
/* $NetBSD: uscsi_subr.c,v 1.1 2008/05/14 16:49:48 reinoud Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Charles M. Hannum; Jason R. Thorpe of the Numerical Aerospace
* Simulation Facility, NASA Ames Research Center.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Small changes, generalisations and Linux support by Reinoud Zandijk
* <reinoud@netbsd.org>.
*
*/
/*
* SCSI support subroutines.
*/
#include <sys/param.h>
#include <sys/ioctl.h>
#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <inttypes.h>
#include <assert.h>
#include "uscsilib.h"
int uscsilib_verbose = 0;
#ifdef USCSI_SCSIPI
/*
* scsipi is a integrated SCSI and ATAPI layer under NetBSD and exists
* in a modified form under OpenBSD and possibly also under other
* operating systems.
*/
#include <sys/scsiio.h>
#ifdef __OpenBSD__
#include <scsi/uscsi_all.h>
#else
#include <dev/scsipi/scsipi_all.h>
#endif
int
uscsi_open(struct uscsi_dev *disc)
{
struct stat dstat;
disc->fhandle = open(disc->dev_name, O_RDWR, 0); /* no create */
if (disc->fhandle<0) {
perror("Failure to open device or file");
return ENODEV;
}
if (fstat(disc->fhandle, &dstat) < 0) {
perror("Can't stat device or file");
uscsi_close(disc);
return ENODEV;
}
return 0;
}
int
uscsi_close(struct uscsi_dev * disc)
{
close(disc->fhandle);
disc->fhandle = -1;
return 0;
}
int
uscsi_command(int flags, struct uscsi_dev *disc,
void *cmd, size_t cmdlen, void *data, size_t datalen,
uint32_t timeout, struct uscsi_sense *uscsi_sense)
{
scsireq_t req;
memset(&req, 0, sizeof(req));
if (uscsi_sense)
bzero(uscsi_sense, sizeof(struct uscsi_sense));
memcpy(req.cmd, cmd, cmdlen);
req.cmdlen = cmdlen;
req.databuf = data;
req.datalen = datalen;
req.timeout = timeout;
req.flags = flags;
req.senselen = SENSEBUFLEN;
if (ioctl(disc->fhandle, SCIOCCOMMAND, &req) == -1)
err(1, "SCIOCCOMMAND");
if (req.retsts == SCCMD_OK)
return 0;
/* Some problem; report it and exit. */
if (req.retsts == SCCMD_TIMEOUT) {
if (uscsilib_verbose)
fprintf(stderr, "%s: SCSI command timed out\n",
disc->dev_name);
return EAGAIN;
} else if (req.retsts == SCCMD_BUSY) {
if (uscsilib_verbose)
fprintf(stderr, "%s: device is busy\n",
disc->dev_name);
return EBUSY;
} else if (req.retsts == SCCMD_SENSE) {
if (uscsi_sense) {
uscsi_sense->asc = req.sense[12];
uscsi_sense->ascq = req.sense[13];
uscsi_sense->skey_valid = req.sense[15] & 128;
uscsi_sense->sense_key = (req.sense[16] << 8) |
(req.sense[17]);
}
if (uscsilib_verbose)
uscsi_print_sense((char *) disc->dev_name,
req.cmd, req.cmdlen,
req.sense, req.senselen_used, 1);
return EIO;
} else
if (uscsilib_verbose)
fprintf(stderr, "%s: device had unknown status %x\n",
disc->dev_name,
req.retsts);
return EFAULT;
}
/*
* The reasoning behind this explicit copy is for compatibility with changes
* in our uscsi_addr structure.
*/
int
uscsi_identify(struct uscsi_dev *disc, struct uscsi_addr *saddr)
{
struct scsi_addr raddr;
int error;
bzero(saddr, sizeof(struct scsi_addr));
error = ioctl(disc->fhandle, SCIOCIDENTIFY, &raddr);
if (error) return error;
#ifdef __NetBSD__
/* scsi and atapi are split up like in uscsi_addr */
if (raddr.type == 0) {
saddr->type = USCSI_TYPE_SCSI;
saddr->addr.scsi.scbus = raddr.addr.scsi.scbus;
saddr->addr.scsi.target = raddr.addr.scsi.target;
saddr->addr.scsi.lun = raddr.addr.scsi.lun;
} else {
saddr->type = USCSI_TYPE_ATAPI;
saddr->addr.atapi.atbus = raddr.addr.atapi.atbus;
saddr->addr.atapi.drive = raddr.addr.atapi.drive;
}
#endif
#ifdef __OpenBSD__
/* atapi's are shown as SCSI devices */
if (raddr.type == 0) {
saddr->type = USCSI_TYPE_SCSI;
saddr->addr.scsi.scbus = raddr.scbus;
saddr->addr.scsi.target = raddr.target;
saddr->addr.scsi.lun = raddr.lun;
} else {
saddr->type = USCSI_TYPE_ATAPI;
saddr->addr.atapi.atbus = raddr.scbus; /* overload */
saddr->addr.atapi.drive = raddr.target; /* overload */
}
#endif
return 0;
}
int
uscsi_check_for_scsi(struct uscsi_dev *disc)
{
struct uscsi_addr saddr;
return uscsi_identify(disc, &saddr);
}
#endif /* SCSILIB_SCSIPI */
#ifdef USCSI_LINUX_SCSI
/*
* Support code for Linux SCSI code. It uses the ioctl() way of
* communicating since this is more close to the origional NetBSD
* scsipi implementation.
*/
#include <scsi/sg.h>
#include <scsi/scsi.h>
#define SENSEBUFLEN 48
int
uscsi_open(struct uscsi_dev * disc)
{
int flags;
struct stat stat;
/* in Linux we are NOT allowed to open it blocking */
/* no create! */
disc->fhandle = open(disc->dev_name, O_RDWR | O_NONBLOCK, 0);
if (disc->fhandle<0) {
perror("Failure to open device or file");
return ENODEV;
}
/* explicitly mark it non blocking (again) (silly Linux) */
flags = fcntl(disc->fhandle, F_GETFL);
flags &= ~O_NONBLOCK;
fcntl(disc->fhandle, F_SETFL, flags);
if (fstat(disc->fhandle, &stat) < 0) {
perror("Can't stat device or file");
uscsi_close(disc);
return ENODEV;
}
return 0;
}
int
uscsi_close(struct uscsi_dev * disc)
{
close(disc->fhandle);
disc->fhandle = -1;
return 0;
}
int
uscsi_command(int flags, struct uscsi_dev *disc,
void *cmd, size_t cmdlen,
void *data, size_t datalen,
uint32_t timeout, struct uscsi_sense *uscsi_sense)
{
struct sg_io_hdr req;
uint8_t sense_buffer[SENSEBUFLEN];
int error;
bzero(&req, sizeof(req));
if (flags == SG_DXFER_FROM_DEV) bzero(data, datalen);
req.interface_id = 'S';
req.dxfer_direction = flags;
req.cmd_len = cmdlen;
req.mx_sb_len = SENSEBUFLEN;
req.iovec_count = 0;
req.dxfer_len = datalen;
req.dxferp = data;
req.cmdp = cmd;
req.sbp = sense_buffer;
req.flags = 0;
req.timeout = timeout;
error = ioctl(disc->fhandle, SG_IO, &req);
if (req.status) {
/* Is this OK? */
if (uscsi_sense) {
uscsi_sense->asc = sense_buffer[12];
uscsi_sense->ascq = sense_buffer[13];
uscsi_sense->skey_valid = sense_buffer[15] & 128;
uscsi_sense->sense_key = (sense_buffer[16] << 8) |
(sense_buffer[17]);
}
if (uscsilib_verbose) {
uscsi_print_sense((char *) disc->dev_name,
cmd, cmdlen, sense_buffer, req.sb_len_wr, 1);
}
}
return error;
}
int
uscsi_identify(struct uscsi_dev *disc, struct uscsi_addr *saddr)
{
struct sg_scsi_id sg_scsi_id;
struct sg_id {
/* target | lun << 8 | channel << 16 | low_ino << 24 */
uint32_t tlci;
uint32_t uniq_id;
} sg_id;
int emulated;
int error;
/* clean result */
bzero(saddr, sizeof(struct uscsi_addr));
/* check if its really SCSI or emulated SCSI (ATAPI f.e.) */
saddr->type = USCSI_TYPE_SCSI;
ioctl(disc->fhandle, SG_EMULATED_HOST, &emulated);
if (emulated) saddr->type = USCSI_TYPE_ATAPI;
/* try 2.4 kernel or older */
error = ioctl(disc->fhandle, SG_GET_SCSI_ID, &sg_scsi_id);
if (!error) {
saddr->addr.scsi.target = sg_scsi_id.scsi_id;
saddr->addr.scsi.lun = sg_scsi_id.lun;
saddr->addr.scsi.scbus = sg_scsi_id.channel;
return 0;
}
/* 2.6 kernel or newer */
error = ioctl(disc->fhandle, SCSI_IOCTL_GET_IDLUN, &sg_id);
if (error) return error;
saddr->addr.scsi.target = (sg_id.tlci ) & 0xff;
saddr->addr.scsi.lun = (sg_id.tlci >> 8) & 0xff;
saddr->addr.scsi.scbus = (sg_id.tlci >> 16) & 0xff;
return 0;
}
int uscsi_check_for_scsi(struct uscsi_dev *disc) {
struct uscsi_addr saddr;
return uscsi_identify(disc, &saddr);
}
#endif /* USCSI_LINUX_SCSI */
#ifdef USCSI_FREEBSD_CAM
int
uscsi_open(struct uscsi_dev *disc)
{
disc->devhandle = cam_open_device(disc->dev_name, O_RDWR);
if (disc->devhandle == NULL) {
disc->fhandle = open(disc->dev_name, O_RDWR | O_NONBLOCK, 0);
if (disc->fhandle < 0) {
perror("Failure to open device or file");
return ENODEV;
}
}
return 0;
}
int
uscsi_close(struct uscsi_dev *disc)
{
if (disc->devhandle != NULL) {
cam_close_device(disc->devhandle);
disc->devhandle = NULL;
} else {
close(disc->fhandle);
disc->fhandle = -1;
}
return 0;
}
int
uscsi_command(int flags, struct uscsi_dev *disc,
void *cmd, size_t cmdlen,
void *data, size_t datalen,
uint32_t timeout, struct uscsi_sense *uscsi_sense)
{
struct cam_device *cam_dev;
struct scsi_sense_data *cam_sense_data;
union ccb ccb;
uint32_t cam_sense;
uint8_t *keypos;
int camflags;
memset(&ccb, 0, sizeof(ccb));
cam_dev = (struct cam_device *) disc->devhandle;
if (datalen == 0) flags = SCSI_NODATACMD;
/* optional : */
/* if (data) assert(flags == SCSI_NODATACMD); */
camflags = CAM_DIR_NONE;
if (flags & SCSI_READCMD)
camflags = CAM_DIR_IN;
if (flags & SCSI_WRITECMD)
camflags = CAM_DIR_OUT;
cam_fill_csio(
&ccb.csio,
0, /* retries */
NULL, /* cbfcnp */
camflags, /* flags */
MSG_SIMPLE_Q_TAG, /* tag_action */
(u_int8_t *) data, /* data_ptr */
datalen, /* dxfer_len */
SSD_FULL_SIZE, /* sense_len */
cmdlen, /* cdb_len */
timeout /* timeout */
);
/* Disable freezing the device queue */
ccb.ccb_h.flags |= CAM_DEV_QFRZDIS;
memcpy(ccb.csio.cdb_io.cdb_bytes, cmd, cmdlen);
/* Send the command down via the CAM interface */
if (cam_send_ccb(cam_dev, &ccb) < 0) {
err(1, "cam_send_ccb");
}
if ((ccb.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP)
return 0;
/* print error using the uscsi_sense routines? */
cam_sense = (ccb.ccb_h.status & (CAM_STATUS_MASK | CAM_AUTOSNS_VALID));
if (cam_sense != (CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID))
return EFAULT;
/* drive responds with sense information */
if (!uscsilib_verbose)
return EFAULT;
/* print sense info */
cam_sense_data = &ccb.csio.sense_data;
if (uscsi_sense) {
uscsi_sense->asc = cam_sense_data->add_sense_code;
uscsi_sense->ascq = cam_sense_data->add_sense_code_qual;
keypos = cam_sense_data->sense_key_spec;
uscsi_sense->skey_valid = keypos[0] & 128;
uscsi_sense->sense_key = (keypos[1] << 8) | (keypos[2]);
}
uscsi_print_sense((char *) disc->dev_name,
cmd, cmdlen,
(uint8_t *) cam_sense_data, 8 + cam_sense_data->extra_len, 1);
return EFAULT;
}
int
uscsi_identify(struct uscsi_dev *disc, struct uscsi_addr *saddr)
{
struct cam_device *cam_dev;
/* clean result */
bzero(saddr, sizeof(struct uscsi_addr));
cam_dev = (struct cam_device *) disc->devhandle;
if (!cam_dev) return ENODEV;
/* check if its really SCSI or emulated SCSI (ATAPI f.e.) ? */
saddr->type = USCSI_TYPE_SCSI;
saddr->addr.scsi.target = cam_dev->target_id;
saddr->addr.scsi.lun = cam_dev->target_lun;
saddr->addr.scsi.scbus = cam_dev->bus_id;
return 0;
}
int
uscsi_check_for_scsi(struct uscsi_dev *disc)
{
struct uscsi_addr saddr;
return uscsi_identify(disc, &saddr);
}
#endif /* USCSI_FREEBSD_CAM */
/*
* Generic SCSI funtions also used by the sense printing functionality.
* FreeBSD support has it allready asked for by the CAM.
*/
int
uscsi_mode_sense(struct uscsi_dev *dev,
uint8_t pgcode, uint8_t pctl, void *buf, size_t len)
{
scsicmd cmd;
bzero(buf, len); /* initialise recieving buffer */
bzero(cmd, SCSI_CMD_LEN);
cmd[ 0] = 0x1a; /* MODE SENSE */
cmd[ 1] = 0; /* - */
cmd[ 2] = pgcode | pctl; /* page code and control flags */
cmd[ 3] = 0; /* - */
cmd[ 4] = len; /* length of recieve buffer */
cmd[ 5] = 0; /* control */
return uscsi_command(SCSI_READCMD, dev, &cmd, 6, buf, len, 10000, NULL);
}
int
uscsi_mode_select(struct uscsi_dev *dev,
uint8_t byte2, void *buf, size_t len)
{
scsicmd cmd;
bzero(cmd, SCSI_CMD_LEN);
cmd[ 0] = 0x15; /* MODE SELECT */
cmd[ 1] = 0x10 | byte2; /* SCSI-2 page format select */
cmd[ 4] = len; /* length of page settings */
cmd[ 5] = 0; /* control */
return uscsi_command(SCSI_WRITECMD, dev, &cmd, 6, buf, len,
10000, NULL);
}
int
uscsi_request_sense(struct uscsi_dev *dev, void *buf, size_t len)
{
scsicmd cmd;
bzero(buf, len); /* initialise recieving buffer */
bzero(cmd, SCSI_CMD_LEN);
cmd[ 0] = 0x03; /* REQUEST SENSE */
cmd[ 4] = len; /* length of data to be read */
cmd[ 5] = 0; /* control */
return uscsi_command(SCSI_WRITECMD, dev, &cmd, 6, buf, len,
10000, NULL);
}
/* end of uscsi_subr.c */

View File

@ -0,0 +1,108 @@
/* $NetBSD: uscsilib.h,v 1.1 2008/05/14 16:49:48 reinoud Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
* NASA Ames Research Center.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Small changes made by Reinoud Zandijk <reinoud@netbsd.org>
*
*/
#ifndef _SCSILIB_H_
#define _SCSILIB_H_
#define SCSI_CMD_LEN 12
typedef unsigned char scsicmd[SCSI_CMD_LEN];
#include "defs.h"
#include "uscsilib_machdep.h"
extern int uscsilib_verbose;
/*
* Unified structure copied and modified from NetBSD's <sys/scsiio.h> for ease
*/
struct uscsi_addr {
int type; /* bus type */
#define USCSI_TYPE_SCSI 0
#define USCSI_TYPE_ATAPI 1
union {
struct {
int scbus; /* -1 if wildcard */
int target; /* -1 if wildcard */
int lun; /* -1 if wildcard */
} scsi;
struct {
int atbus; /* -1 if wildcard */
int drive; /* -1 if wildcard */
} atapi;
} addr;
};
struct uscsi_sense {
int asc; /* Additional sense code */
int ascq; /* Additional sense code quality */
int skey_valid; /* sense key valid */
int sense_key; /* sense key; interpret on (asc, ascq) pair */
};
struct uscsi_dev {
char *dev_name;
int fhandle;
void *devhandle; /* for if a fhandle is not enough */
};
/* uscsi_sense.c */
extern char *uscsi_decode_sense(void *sinfo, int flag);
extern void uscsi_print_sense(const char *name, u_char *req_cmd,
int req_cmdlen, u_char *req_sense, int req_senselen_used,
int verbosity);
/* scsi_subr.c */
extern int uscsi_open(struct uscsi_dev *);
extern int uscsi_close(struct uscsi_dev *);
extern int uscsi_command(int flags, struct uscsi_dev *disc,
void *cmd, size_t cmdlen, void *data, size_t datalen,
uint32_t timeout, struct uscsi_sense *uscsi_sense);
extern int uscsi_check_for_scsi(struct uscsi_dev *);
extern int uscsi_identify(struct uscsi_dev *, struct uscsi_addr *saddr);
extern int uscsi_mode_sense(struct uscsi_dev *, u_int8_t, u_int8_t,
void *, size_t);
extern int uscsi_mode_select(struct uscsi_dev *, u_int8_t, void *, size_t);
extern int uscsi_request_sense(struct uscsi_dev *, void *, size_t);
#endif /* _SCSILIB_H_ */

View File

@ -0,0 +1,90 @@
/* $NetBSD: uscsilib_machdep.h,v 1.1 2008/05/14 16:49:48 reinoud Exp $ */
/*
* Copyright (c) 2003, 2004, 2005, 2006, 2008 Reinoud Zandijk
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef _USCSILIB_MACHDEP_H_
#define _USCSILIB_MACHDEP_H_
#ifndef _DEV_SCSIPI_SCSIPI_ALL_H_
# define SSD_KEY 0x0F
# define SSD_ILI 0x20
# define SSD_EOM 0x40
# define SSD_FILEMARK 0x80
# define SKEY_NO_SENSE 0x00
# define SKEY_RECOVERED_ERROR 0x01
# define SKEY_NOT_READY 0x02
# define SKEY_MEDIUM_ERROR 0x03
# define SKEY_HARDWARE_ERROR 0x04
# define SKEY_ILLEGAL_REQUEST 0x05
# define SKEY_UNIT_ATTENTION 0x06
# define SKEY_WRITE_PROTECT 0x07
# define SKEY_BLANK_CHECK 0x08
# define SKEY_VENDOR_UNIQUE 0x09
# define SKEY_COPY_ABORTED 0x0A
# define SKEY_ABORTED_COMMAND 0x0B
# define SKEY_EQUAL 0x0C
# define SKEY_VOLUME_OVERFLOW 0x0D
# define SKEY_MISCOMPARE 0x0E
# define SKEY_RESERVED 0x0F
#endif
#ifndef SCSI
# define SCSI_READCMD 0
# define SCSI_WRITECMD 0
struct scsi_addr;
int scsilib_verbose;
#endif
#ifdef USCSI_SCSIPI
# include <sys/scsiio.h>
# define SCSI_READCMD SCCMD_READ
# define SCSI_WRITECMD SCCMD_WRITE
# define SCSI_NODATACMD SCCMD_WRITE
#endif
#ifdef USCSI_LINUX_SCSI
# include <scsi/sg.h>
# define SCSI_READCMD SG_DXFER_FROM_DEV
# define SCSI_WRITECMD SG_DXFER_TO_DEV
# define SCSI_NODATACMD SC_DXFER_NONE
#endif
#ifdef USCSI_FREEBSD_CAM
# include <camlib.h>
# include <cam/scsi/scsi_message.h>
# define SCSI_READCMD 1
# define SCSI_WRITECMD 2
# define SCSI_NODATACMD 0
#endif
#endif /* _USCSILIB_MACHDEP_H_ */