Index: iet-0.4.8/Makefile diff -u iet-0.4.8/Makefile:1.1.1.1 iet-0.4.8/Makefile:1.4 --- iet-0.4.8/Makefile:1.1.1.1 Tue May 24 12:44:12 2005 +++ iet-0.4.8/Makefile Tue May 24 13:34:22 2005 @@ -17,7 +17,13 @@ all: progs mods -mods: +CSSSRC = kernel/css-auth.c kernel/css-auth.h kernel/css.h kernel/csstable.c +kernel/css-auth.c: css-auth/css-auth.c + sed -e 's:\(^# *include *.*$$\):/* \1 */:' $< > $@ +kernel/%: css-auth/% + ln -s ../$< $@ + +mods: $(CSSSRC) $(MAKE) -C $(KERNELSRC) SUBDIRS=$(shell pwd)/kernel modules progs: @@ -37,7 +43,7 @@ else \ install -v -m 755 etc/initd/initd /etc/init.d/iscsi-target; \ fi - @eval `sed -n 's/#define UTS_RELEASE /KERNELRELEASE=/p' $(KERNELSRC)/include/linux/version.h`; \ + @eval `sed -n 's/#define UTS_RELEASE /KERNELRELEASE=/p' $(O)/include/linux/version.h`; \ install -vD kernel/iscsi_trgt.ko \ $(INSTALL_MOD_PATH)/lib/modules/$$KERNELRELEASE/kernel/iscsi/iscsi_trgt.ko depmod -aq @@ -45,3 +51,4 @@ clean: $(MAKE) -C usr clean $(MAKE) -C $(KERNELSRC) SUBDIRS=$(shell pwd)/kernel clean + for i in $(CSSSRC); do test -h $$i && $(RM) $$i; done Index: iet-0.4.8/etc/initd/initd.debian diff -u iet-0.4.8/etc/initd/initd.debian:1.1 iet-0.4.8/etc/initd/initd.debian:1.3 --- iet-0.4.8/etc/initd/initd.debian:1.1 Wed May 18 15:32:23 2005 +++ iet-0.4.8/etc/initd/initd.debian Sat May 21 22:37:00 2005 @@ -6,6 +6,9 @@ PID_FILE=/var/run/iscsi_trgt.pid CONFIG_FILE=/etc/ietd.conf +CONFIG_FILE=/ext1/iscsi/wcvs/ietd.conf +f=/home/jro/iscsi/wcvs/ietd.conf +test -f $f && CONFIG_FILE=$f DAEMON=/usr/sbin/ietd PATH=/sbin:/bin:/usr/sbin:/usr/bin @@ -53,9 +56,9 @@ configure_memsize modprobe -q crc32c modprobe iscsi_trgt - start-stop-daemon --start --exec $DAEMON --quiet + start-stop-daemon --start --exec $DAEMON --quiet -- -d0 -c $CONFIG_FILE RETVAL=$? - if [ $RETVAL == "0" ]; then + if [ $RETVAL -eq 0 ]; then echo "succeeded." else echo "failed." @@ -68,7 +71,7 @@ # ugly, but ietadm does not allways provides correct exit values RETURN=`ietadm --op delete 2>&1` RETVAL=$? - if [ $RETVAL == "0" ] && [[ $RETURN != "something wrong" ]]; then + if [ $RETVAL -eq 0 -a ! "$RETURN" = "something wrong" ]; then echo "succeeded." else echo "failed with reason :$RETURN" @@ -78,7 +81,7 @@ echo -n "Stopping iSCSI enterprise target service: " start-stop-daemon --stop --quiet --exec $DAEMON --pidfile $PID_FILE RETVAL=$? - if [ $RETVAL == "0" ]; then + if [ $RETVAL -eq 0 ]; then echo "succeeded." else echo "failed." @@ -90,7 +93,7 @@ modprobe -r iscsi_trgt RETVAL=$? modprobe -r crc32c 2>/dev/null - if [ $RETVAL == "0" ]; then + if [ $RETVAL -eq 0 ]; then echo "succeeded." else echo "failed." @@ -122,13 +125,13 @@ dump) DUMP=`tempfile -p ietd` RETVAL=$? - if [ $RETVAL != "0" ]; then + if [ $RETVAL -ne 0 ]; then echo "Failed to create dump file $DUMP" exit 1 fi ietadm --mode dump --all >$DUMP RETVAL=$? - if [ $RETVAL != "0" ]; then + if [ $RETVAL -ne 0 ]; then echo "Error dumping config from daemon" rm $DUMP exit 1 Index: iet-0.4.8/include/iet_u.h diff -u iet-0.4.8/include/iet_u.h:1.1 iet-0.4.8/include/iet_u.h:1.4 --- iet-0.4.8/include/iet_u.h:1.1 Wed May 18 15:32:23 2005 +++ iet-0.4.8/include/iet_u.h Thu May 26 00:02:39 2005 @@ -1,7 +1,7 @@ #ifndef _IET_U_H #define _IET_U_H -#define IET_VERSION_STRING "0.4.8" +#define IET_VERSION_STRING "0.4.8" "rmmc" /* The maximum length of 223 bytes in the RFC. */ #define ISCSI_NAME_LEN 256 @@ -111,6 +111,9 @@ #define NETLINK_IET 12 +#ifndef __KERNEL__ +#include +#endif #define ADD_TARGET _IOW('i', 0, struct target_info) #define DEL_TARGET _IOW('i', 1, struct target_info) #define START_TARGET _IO('i', 2) @@ -126,4 +129,25 @@ #define ISCSI_PARAM_SET _IOW('i', 12, struct iscsi_param_info) #define ISCSI_PARAM_GET _IOWR('i', 13, struct iscsi_param_info) +static inline unsigned char* +iocmdstr(unsigned int cmd) +{ + switch (cmd) { + case ADD_TARGET: return "ADD_TARGET"; + case DEL_TARGET: return "DEL_TARGET"; + case START_TARGET: return "START_TARGET"; + case STOP_TARGET: return "STOP_TARGET"; + case ADD_VOLUME: return "ADD_VOLUME"; + case DEL_VOLUME: return "DEL_VOLUME"; + case ADD_SESSION: return "ADD_SESSION"; + case DEL_SESSION: return "DEL_SESSION"; + case GET_SESSION_INFO: return "GET_SESSION_INFO"; + case ADD_CONN: return "ADD_CONN"; + case DEL_CONN: return "DEL_CONN"; + case GET_CONN_INFO: return "GET_CONN_INFO"; + case ISCSI_PARAM_SET: return "ISCSI_PARAM_SET"; + case ISCSI_PARAM_GET: return "ISCSI_PARAM_GET"; + } + return "Unknown"; +} #endif Index: iet-0.4.8/include/rmmc_aux.h diff -u /dev/null iet-0.4.8/include/rmmc_aux.h:1.1 --- /dev/null Fri Jun 3 11:12:25 2005 +++ iet-0.4.8/include/rmmc_aux.h Sat May 21 22:37:00 2005 @@ -0,0 +1,158 @@ + +#ifndef rmmc_aux_h +#define rmmc_aux_h + +static char rmmc_aux__h[] __attribute__((unused, nocommon)) += "@(#) $Id: rmmc_aux.h,v 1.1 2005/05/21 13:37:00 jro Exp $"; // " " __DATE__ " " __TIME__ + +//#include +#include + +/* + * file format + */ +struct rmmc_aux_offlen { + u32 offset; + u32 length; +}; + +/* based upon raw responses */ +struct rmmc_aux_discinfo { + u8 data[0]; +}; + +enum {DslPhys, DslCprt, DslManuf, LastDslData}; +struct rmmc_aux_layer { + struct rmmc_aux_offlen offlen[LastDslData]; // offset from next 'data' + u8 data[0]; +}; + +struct rmmc_aux_dvdst { + u8 nlayer; + u8 pad[3]; + u8 dkey[4+2048]; + struct rmmc_aux_offlen offlen[DVD_LAYERS]; // offset from next 'data' + struct rmmc_aux_layer data[0]; +}; + +struct rmmc_aux_tpa { + // un-implemented + u8 data[0]; +}; + +enum {Type1_0, Type1_1, LastType1}; +struct rmmc_aux_trkinfo { + struct rmmc_aux_offlen offlen[LastType1]; // offset from next 'data' + u8 data[0]; +}; + +struct rmmc_aux_tk { + u32 lba[2]; // start and end + u8 cpbits; + u8 tk[5]; + u8 pad[2]; +}; + +struct rmmc_aux_rkey { + u32 ntitle; + struct rmmc_aux_tk data[0]; +}; + +enum { + DISC_INFO, // GPCMD_READ_DISC_INFO + DVD_STRUCTURE, // GPCMD_READ_DVD_STRUCTURE or READ DISC STRUCTURE command + TOC_PMA_ATIP, // GPCMD_READ_TOC_PMA_ATIP + REPORT_KEY, // GPCMD_REPORT_KEY + //TRACK_INFO, // GPCMD_READ_TRACK_RZONE_INFO + LastCmd +}; + +#define RmmcAuxMagicStr "rmmcaux" +struct rmmc_aux_file_v0 { + u8 magic[16]; + u32 version; + u32 size; // all data, should be match to the total of 'length's in 'offlen'' + u32 sum; // sum of all 'data' + u32 salt[4]; + struct rmmc_aux_offlen offlen[LastCmd]; // offset from next 'data' + u8 data[0]; // responses +}; +#define rmmc_aux_file rmmc_aux_file_v0 +/* +#if sizeof(RmmcAuxMagicStr)-1 > sizeof(struct rmmc_aux_file_v0.magic) +#error magic string macro it too long. +#endif +*/ + +static inline void +set_offlen(struct rmmc_aux_offlen p[], u32 offset, u32 length) +{ + p->offset = cpu_to_be32(offset); + p->length = cpu_to_be32(length); +} + +/* + * simple macros for reading the aux file + */ +#define define_ol(name, basetype, lim) \ +static inline void* \ +name(basetype base[], int ind, u32 len[]) \ +{ \ + struct rmmc_aux_offlen *p; \ + u8 *o; \ + /* if (!base || ind >= (lim)) return NULL */; \ + o = (void*)base->data; \ + p = base->offlen; \ + p += ind; \ + *len = be32_to_cpu(p->length); \ + return o+be32_to_cpu(p->offset); \ +} + +define_ol(offlenof_aux, struct rmmc_aux_file, LastCmd); +define_ol(offlenof_dvdst, struct rmmc_aux_dvdst, ((struct rmmc_aux_dvdst*)base)->nlayer); +define_ol(offlenof_layer, struct rmmc_aux_layer, LastDslData); + +static inline struct rmmc_aux_discinfo* +offlen_discinfo(struct rmmc_aux_file aux[], u32 len[]) +{return offlenof_aux(aux, DISC_INFO, len);} +static inline struct rmmc_aux_dvdst* +offlen_dvdst(struct rmmc_aux_file aux[], u32 len[]) +{return offlenof_aux(aux, DVD_STRUCTURE, len);} +static inline struct rmmc_aux_tpa* +offlen_tpa(struct rmmc_aux_file aux[], u32 len[]) +{return offlenof_aux(aux, TOC_PMA_ATIP, len);} +static inline struct rmmc_aux_rkey* +offlen_rkey(struct rmmc_aux_file aux[], u32 len[]) +{return offlenof_aux(aux, REPORT_KEY, len);} + +static inline struct rmmc_aux_layer* +offlen_layer(struct rmmc_aux_dvdst dvdst[], int num, u32 len[]) +{return offlenof_dvdst(dvdst, num, len);} + +static inline struct rmmc_aux_phys* +offlen_phys(struct rmmc_aux_layer layer[], u32 len[]) +{return offlenof_layer(layer, DslPhys, len);} +static inline struct rmmc_aux_cprt* +offlen_cprt(struct rmmc_aux_layer layer[], u32 len[]) +{return offlenof_layer(layer, DslCprt, len);} +static inline u8* +offlen_manuf(struct rmmc_aux_layer layer[], u32 len[]) +{return offlenof_layer(layer, DslManuf, len);} + +/* + * tiny utilities for ietd. + */ +static inline u32 +getu32(u8 a[]) +{return be32_to_cpu(*(u32*)a);} +static inline void +putu32(u8 a[], u32 v) +{v = cpu_to_be32(v); memcpy(a, &v, sizeof(u32));} +static inline u16 +getu16(u8 a[]) +{return be16_to_cpu(*(u16*)a);} +static inline void +putu16(u8 a[], u16 v) +{v = cpu_to_be16(v); memcpy(a, &v, sizeof(u16));} + +#endif //rmmc_aux_h Index: iet-0.4.8/kernel/Makefile diff -u iet-0.4.8/kernel/Makefile:1.1.1.1 iet-0.4.8/kernel/Makefile:1.4 --- iet-0.4.8/kernel/Makefile:1.1.1.1 Tue May 24 12:46:19 2005 +++ iet-0.4.8/kernel/Makefile Wed Jun 1 14:02:46 2005 @@ -7,10 +7,10 @@ # # Note 2! The CFLAGS definitions are now in the main makefile. -EXTRA_CFLAGS += -I$(src)/../include +EXTRA_CFLAGS += -I$(src)/../include -UCONNSTAT obj-m += iscsi_trgt.o iscsi_trgt-objs := tio.o iscsi.o nthread.o wthread.o config.o digest.o \ conn.o session.o target.o volume.o iotype.o \ - file-io.o target_disk.o event.o param.o - + file-io.o target_disk.o event.o param.o \ + rmmc-io.o target_rmmc.o css-auth.o csstable.o Index: iet-0.4.8/kernel/config.c diff -u iet-0.4.8/kernel/config.c:1.1.1.1 iet-0.4.8/kernel/config.c:1.5 --- iet-0.4.8/kernel/config.c:1.1.1.1 Tue May 24 12:46:19 2005 +++ iet-0.4.8/kernel/config.c Tue May 31 13:59:34 2005 @@ -222,6 +222,8 @@ long err; u32 id; + dprintk(D_RMMC, "cmd %s(%d)\n", iocmdstr(cmd), _IOC_NR(cmd)); + if ((err = get_user(id, (u32 *) arg)) != 0) goto done; Index: iet-0.4.8/kernel/conn.c diff -u iet-0.4.8/kernel/conn.c:1.1.1.1 iet-0.4.8/kernel/conn.c:1.9 --- iet-0.4.8/kernel/conn.c:1.1.1.1 Tue May 24 12:46:19 2005 +++ iet-0.4.8/kernel/conn.c Tue May 31 13:59:34 2005 @@ -11,6 +11,9 @@ #include "iscsi.h" #include "iscsi_dbg.h" #include "digest.h" +#ifdef CONNSTAT +#include "scsiop.h" +#endif void print_conn_state(struct seq_file *seq, unsigned long state) { @@ -34,6 +37,20 @@ addr(dest,24), addr(dest,16), addr(dest, 8), addr(dest, 0)); print_conn_state(seq, conn->state); seq_printf(seq, " hd: %d dd: %d\n", conn->hdigest_type, conn->ddigest_type); + +#ifdef CONNSTAT + { + int i; + for (i = 0; i < sizeof(conn->opstat)/sizeof(conn->opstat[0]); i++) + if (atomic_read(&conn->opstat[i].success) + || atomic_read(&conn->opstat[i].failure)) + seq_printf(seq, " op %02x: %10u %10u, %s\n", + i, + atomic_read(&conn->opstat[i].success), + atomic_read(&conn->opstat[i].failure), + opstr(i)); + } +#endif } } @@ -109,6 +126,13 @@ list_del(&conn->poll_list); digest_cleanup(conn); + + { + struct target_type *type; + type = target_type_array[conn->session->target->trgt_param.target_type]; + if (type && type->conn_free) + type->conn_free(conn); + } kfree(conn); return 0; @@ -125,6 +149,14 @@ return -ENOMEM; memset(conn, 0, sizeof(*conn)); + { + struct target_type *type; + type = target_type_array[session->target->trgt_param.target_type]; + if (type && type->conn_alloc + && type->conn_alloc(conn)) + goto err; + } + conn->session = session; conn->cid = info->cid; conn->stat_sn = info->stat_sn; @@ -133,6 +165,7 @@ conn->hdigest_type = info->header_digest; conn->ddigest_type = info->data_digest; if (digest_init(conn) < 0) { + err: kfree(conn); return -ENOMEM; } @@ -150,6 +183,10 @@ conn->file = fget(info->fd); iet_socket_bind(conn); + +#ifdef CONNSTAT + memset(conn->opstat, 0, sizeof(conn->opstat)); +#endif list_add(&conn->poll_list, &session->target->nthread_info.active_conns); Index: iet-0.4.8/kernel/file-io.c diff -u iet-0.4.8/kernel/file-io.c:1.1.1.1 iet-0.4.8/kernel/file-io.c:1.6 --- iet-0.4.8/kernel/file-io.c:1.1.1.1 Tue May 24 12:46:19 2005 +++ iet-0.4.8/kernel/file-io.c Thu May 26 00:02:39 2005 @@ -11,11 +11,7 @@ #include "iscsi.h" #include "iscsi_dbg.h" #include "iotype.h" - -struct fileio_data { - char *path; - struct file *filp; -}; +#include "file-io.h" static int fileio_make_request(struct iet_volume *lu, struct tio *tio, int rw) { @@ -58,8 +54,10 @@ set_fs(oldfs); - if (ret != count) + if (ret != count) { eprintk("I/O error %lld, %ld\n", count, (long) ret); + return -1; + } size -= count; offset = 0; @@ -127,7 +125,8 @@ return 0; } -static void gen_scsiid(struct iet_volume *volume, struct inode *inode) +//static +void gen_scsiid(struct iet_volume *volume, struct inode *inode) { int i; unsigned int *p = (unsigned int *) volume->scsi_id; Index: iet-0.4.8/kernel/file-io.h diff -u /dev/null iet-0.4.8/kernel/file-io.h:1.2 --- /dev/null Fri Jun 3 11:12:25 2005 +++ iet-0.4.8/kernel/file-io.h Tue May 31 20:14:47 2005 @@ -0,0 +1,11 @@ + +#ifndef file_io_h +#define file_io_h +// extracted from ./file-io.c in order to share. + +struct fileio_data { + char *path; + struct file *filp; +}; + +#endif //file_io_h Index: iet-0.4.8/kernel/iotype.c diff -u iet-0.4.8/kernel/iotype.c:1.1.1.1 iet-0.4.8/kernel/iotype.c:1.2 --- iet-0.4.8/kernel/iotype.c:1.1.1.1 Tue May 24 12:46:19 2005 +++ iet-0.4.8/kernel/iotype.c Sat May 21 22:37:00 2005 @@ -78,6 +78,7 @@ struct iotype *iotype_array[] = { &fileio, + &rmmcio }; int iotype_init(void) Index: iet-0.4.8/kernel/iotype.h diff -u iet-0.4.8/kernel/iotype.h:1.1.1.1 iet-0.4.8/kernel/iotype.h:1.2 --- iet-0.4.8/kernel/iotype.h:1.1.1.1 Tue May 24 12:46:19 2005 +++ iet-0.4.8/kernel/iotype.h Sat May 21 22:37:00 2005 @@ -20,6 +20,7 @@ }; extern struct iotype fileio; +extern struct iotype rmmcio; extern int iotype_init(void); extern void iotype_exit(void); Index: iet-0.4.8/kernel/iscsi.c diff -u iet-0.4.8/kernel/iscsi.c:1.1.1.1 iet-0.4.8/kernel/iscsi.c:1.8 --- iet-0.4.8/kernel/iscsi.c:1.1.1.1 Tue May 24 12:46:19 2005 +++ iet-0.4.8/kernel/iscsi.c Tue May 31 13:59:34 2005 @@ -6,6 +6,7 @@ #include #include +#include // jro #include #include @@ -318,8 +319,16 @@ rsp_hdr->residual_count = cpu_to_be32(size); } - if (func(req) < 0) + if (func(req) < 0) { +#ifdef CONNSTAT + atomic_inc(&req->conn->opstat[cmnd_hdr(req)->scb[0]].failure); +#endif eprintk("%x\n", cmnd_opcode(req)); + } +#ifdef CONNSTAT + else + atomic_inc(&req->conn->opstat[cmnd_hdr(req)->scb[0]].success); +#endif iscsi_cmnd_init_write(rsp); } @@ -364,10 +373,17 @@ struct iscsi_cmnd *rsp; if (func(req) < 0) { +#ifdef CONNSTAT + atomic_inc(&req->conn->opstat[cmnd_hdr(req)->scb[0]].failure); +#endif rsp = create_sense_rsp(req, ILLEGAL_REQUEST, 0x24, 0x0); iscsi_cmnd_init_write(rsp); - } else + } else { +#ifdef CONNSTAT + atomic_inc(&req->conn->opstat[cmnd_hdr(req)->scb[0]].success); +#endif do_send_data_rsp(req); + } } /** @@ -707,6 +723,11 @@ *off = be64_to_cpu(*(u64 *)&cmd[2]); *len = be32_to_cpu(*(u32 *)&cmd[10]); break; + case GPCMD_SEND_KEY: + *off = 0; + *len = be16_to_cpu(*(u16*)(cmd+8)); + //break; + return; default: BUG(); } @@ -910,6 +931,22 @@ case RELEASE: case RESERVE_10: case RELEASE_10: +/* jro: mmc cmnds */ + case GPCMD_READ_DVD_STRUCTURE: + case GPCMD_REPORT_KEY: + case GPCMD_READ_TOC_PMA_ATIP: + case GPCMD_MODE_SENSE_10: + case GPCMD_GET_EVENT_STATUS_NOTIFICATION: + case GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL: + + case GPCMD_READ_DISC_INFO: + case GPCMD_SEEK: + case GPCMD_GET_CONFIGURATION: + case GPCMD_READ_TRACK_RZONE_INFO: + case GPCMD_READ_SUBCHANNEL: + case GPCMD_READ_CD_MSF: + case GPCMD_READ_CD: +/* end of mmc cmnds */ { if (!(req_hdr->flags & ISCSI_CMD_FINAL) || req->pdu.datasize) { /* unexpected unsolicited data */ @@ -934,7 +971,7 @@ } set_offset_and_length(req->lun, req_hdr->scb, &offset, &length); - req->tio = tio_alloc(get_pgcnt(length, offset)); + req->tio = _tio_alloc(get_pgcnt(length, offset), 0); // allocate pages later. tio_set(req->tio, length, offset); break; } @@ -942,6 +979,7 @@ case WRITE_10: case WRITE_16: case WRITE_VERIFY: + case GPCMD_SEND_KEY: // jro: mmc cmnd { struct iscsi_sess_param *param = &conn->session->param; loff_t offset; @@ -1638,6 +1676,12 @@ { int err = -ENOMEM; + // jro + //memset(&debug_enable_flags, 0xff, sizeof(debug_enable_flags)); + //debug_enable_flags = D_SETUP|D_GENERIC|D_READ|D_IOD|D_IOMODE; + debug_enable_flags = D_RMMC; + //debug_enable_flags |= D_SETUP; + //debug_enable_flags |= D_GENERIC; printk("iSCSI Enterprise Target Software - version %s\n", IET_VERSION_STRING); if ((ctr_major = register_chrdev(0, ctr_name, &ctr_fops)) < 0) { Index: iet-0.4.8/kernel/iscsi.h diff -u iet-0.4.8/kernel/iscsi.h:1.1.1.1 iet-0.4.8/kernel/iscsi.h:1.9 --- iet-0.4.8/kernel/iscsi.h:1.1.1.1 Tue May 24 12:46:19 2005 +++ iet-0.4.8/kernel/iscsi.h Tue May 31 13:59:35 2005 @@ -41,6 +41,7 @@ struct tio { u32 pg_cnt; + u32 need_pages; pgoff_t idx; u32 offset; @@ -82,11 +83,14 @@ }; struct iscsi_cmnd; +struct iscsi_conn; struct target_type { int id; int (*execute_cmnd) (struct iscsi_cmnd *); + int (*conn_alloc)(struct iscsi_conn *); + int (*conn_free)(struct iscsi_conn *); }; enum iscsi_device_state { @@ -112,7 +116,7 @@ struct semaphore target_sem; - int target_type; + //int target_type; }; struct iscsi_queue { @@ -215,6 +219,15 @@ struct crypto_tfm *rx_digest_tfm; struct crypto_tfm *tx_digest_tfm; + +#ifdef CONNSTAT + /* statistics */ + struct { + atomic_t success, failure; + } opstat[0xff]; +#endif + + void *private; }; struct iscsi_pdu { @@ -319,13 +332,15 @@ /* tio.c */ extern int tio_init(void); extern void tio_exit(void); -extern struct tio *tio_alloc(int); +extern struct tio *_tio_alloc(int, int); +#define tio_alloc(n) _tio_alloc((n), 1) extern void tio_get(struct tio *); extern void tio_put(struct tio *); extern void tio_set(struct tio *, u32, loff_t); extern int tio_read(struct iet_volume *, struct tio *); extern int tio_write(struct iet_volume *, struct tio *); extern int tio_sync(struct iet_volume *, struct tio *); +extern int tio_add_pages(struct tio *, int); /* iotype.c */ extern struct iotype *get_iotype(const char *name); @@ -336,6 +351,9 @@ /* target_disk.c */ extern struct target_type disk_ops; + +/* target_rmmc.c */ +extern struct target_type rmmc_ops; /* event.c */ extern int event_send(u32, u64, u32, u32, int); Index: iet-0.4.8/kernel/iscsi_dbg.h diff -u iet-0.4.8/kernel/iscsi_dbg.h:1.1.1.1 iet-0.4.8/kernel/iscsi_dbg.h:1.3 --- iet-0.4.8/kernel/iscsi_dbg.h:1.1.1.1 Tue May 24 12:46:19 2005 +++ iet-0.4.8/kernel/iscsi_dbg.h Mon May 23 19:33:45 2005 @@ -10,6 +10,7 @@ #define D_THREAD (1UL << 6) #define D_TASK_MGT (1UL << 7) #define D_IOMODE (1UL << 8) +#define D_RMMC (1UL << 9) #define D_DATA (D_READ | D_WRITE) @@ -18,19 +19,19 @@ #define dprintk(debug, fmt, args...) \ do { \ if ((debug) & debug_enable_flags) { \ - printk("%s(%d) " fmt, __FUNCTION__, __LINE__, args); \ + printk("%s(%d):%d: " fmt, __FUNCTION__, __LINE__, current->pid, args); \ } \ } while (0) #define eprintk(fmt, args...) \ do { \ - printk("%s(%d) " fmt, __FUNCTION__, __LINE__, args); \ + printk("%s(%d):%d: " fmt, __FUNCTION__, __LINE__, current->pid, args); \ } while (0) #define assert(p) do { \ if (!(p)) { \ - printk(KERN_CRIT "BUG at %s:%d assert(%s)\n", \ - __FILE__, __LINE__, #p); \ + printk(KERN_CRIT "BUG at %s:%d:%d assert(%s)\n", \ + __FILE__, __LINE__, current->pid, #p); \ dump_stack(); \ BUG(); \ } \ Index: iet-0.4.8/kernel/param.c diff -u iet-0.4.8/kernel/param.c:1.1.1.1 iet-0.4.8/kernel/param.c:1.2 --- iet-0.4.8/kernel/param.c:1.1.1.1 Tue May 24 12:46:19 2005 +++ iet-0.4.8/kernel/param.c Sat May 21 22:37:00 2005 @@ -10,6 +10,7 @@ struct target_type *target_type_array[] = { &disk_ops, + &rmmc_ops }; #define CHECK_PARAM(info, iparam, word, min, max) \ Index: iet-0.4.8/kernel/rmmc-io.c diff -u /dev/null iet-0.4.8/kernel/rmmc-io.c:1.11 --- /dev/null Fri Jun 3 11:12:25 2005 +++ iet-0.4.8/kernel/rmmc-io.c Wed Jun 1 12:57:03 2005 @@ -0,0 +1,364 @@ +/* + * Target device file I/O for read-only(or reduced) mmc + * (C) 2004-2005 Junjiro Okajima + * This code is licenced under the GPL. + * + * based on ietd file-io.c, which was + * (C) 2004 Fujita Tomonori + * licensed under the terms of the GPL. + */ + +static char rmmc_io_c[] __attribute__((unused, nocommon)) += "@(#) $Id: rmmc-io.c,v 1.11 2005/06/01 03:57:03 jro Exp $"; // " " __DATE__ " " __TIME__ + +#include "iscsi_dbg.h" +#include "iotype.h" +#include "rmmc-io.h" + +static spinlock_t auxinfo_lock = SPIN_LOCK_UNLOCKED; +static LIST_HEAD(auxinfo_list); +static DECLARE_MUTEX(auxinfo_sema); + +#define AuxExt ".aux" + +/* + * before calling me, you should lock the list + */ +static inline struct auxinfo* +lookup_auxinfo(u8 auxpath[]) +{ + struct auxinfo *e; + + list_for_each_entry(e, &auxinfo_list, list) + if (e->auxpath && strcmp(e->auxpath, auxpath) == 0) // slow? + return e; + return NULL; +} + +static struct auxinfo* +auxinfo_alloc(char auxpath[], int err[]) +{ + struct auxinfo *e; + void *label; + mm_segment_t oldfs; + struct file *filp = NULL; + struct inode *inode; + int n; + + *err = -ENOMEM; + e = kmalloc(sizeof(struct auxinfo), GFP_KERNEL); + if (!e) return NULL; + //dprintk(D_RMMC, "auxinfo %p\n", e); + label = &&err; + e->auxpath = kmalloc(strlen(auxpath)+1, GFP_KERNEL); + if (!e->auxpath) goto *label; + strcpy(e->auxpath, auxpath); + //dprintk(D_RMMC, "auxpath %p\n", e->auxpath); + label = &&err1; + + oldfs = get_fs(); + set_fs(get_ds()); + filp = filp_open(auxpath, O_RDONLY|O_LARGEFILE, 0); + set_fs(oldfs); + if (IS_ERR(filp)) { + *err = PTR_ERR(filp); + goto *label; + } + label = &&err2; + + inode = filp->f_dentry->d_inode; + *err = -ESPIPE; + //dprintk(D_RMMC, "i_size %Lu\n", inode->i_size); + *err = -ENOMEM; + e->auxfile = kmalloc(inode->i_size, GFP_KERNEL); + if (!e->auxfile) goto *label; + //dprintk(D_RMMC, "auxfile %p\n", e->auxfile); + label = &&err3; + + *err = -EIO; + n = kernel_read(filp, 0, (void*)e->auxfile, inode->i_size); + filp_close(filp, NULL); + filp = NULL; + if (n != inode->i_size) goto *label; + + INIT_LIST_HEAD(&e->list); + atomic_set(&e->ref, 1); + + return e; + err3: + kfree(e->auxfile); + err2: + if (filp) filp_close(filp, NULL); + err1: + kfree(e->auxpath); + err: + kfree(e); + return NULL; +} + +/* + * before calling me, you should lock the list + * returns TRUE if it is freed, FALSE if not. + */ +static inline int +auxinfo_unref(struct auxinfo e[]) +{ + int ret = 0; + + if (!atomic_dec_and_test(&e->ref)) goto end; + + ret = -1; + list_del(&e->list); + //dprintk(D_RMMC, "freeing %p{%p, %p}\n", e, e->auxpath, e->auxfile); + kfree(e->auxfile); + kfree(e->auxpath); + kfree(e); + end: + return ret; +} + +static int +getauxinfo(struct rmmcio_volume p[]) +{ + int res; + int n = strlen(p->fileio_data->path); + char auxpath[n+sizeof(AuxExt)]; + + strcpy(auxpath, p->fileio_data->path); + strcpy(auxpath+n, AuxExt); + + spin_lock(&auxinfo_lock); + p->auxinfo = lookup_auxinfo(auxpath); + if (p->auxinfo) { + atomic_inc(&p->auxinfo->ref); + spin_unlock(&auxinfo_lock); + //dprintk(D_RMMC, "sharing aux of %s\n", auxpath); + return 0; + } + spin_unlock(&auxinfo_lock); + + down(&auxinfo_sema); + // search again + spin_lock(&auxinfo_lock); + p->auxinfo = lookup_auxinfo(auxpath); + if (p->auxinfo) { + atomic_inc(&p->auxinfo->ref); + spin_unlock(&auxinfo_lock); + //dprintk(D_RMMC, "sharing aux of %s\n", auxpath); + return 0; + } + spin_unlock(&auxinfo_lock); + + dprintk(D_RMMC, "creating aux for %s\n", auxpath); + p->auxinfo = auxinfo_alloc(auxpath, &res); + if (!p->auxinfo) goto end; + +#if 0 + { + struct rmmc_aux_dvdst *dvdst; + struct rmmc_aux_rkey *rkey; + struct rmmc_aux_tk *tk; + u32 len; + + res = -EDOM; + dprintk(D_RMMC, "%s %d\n", + p->auxinfo->auxfile->magic, p->auxinfo->auxfile->version); + dvdst = offlen_dvdst(p->auxinfo->auxfile, &len); + if (!dvdst) goto end; + dprintk(D_RMMC, "layers %d\n", dvdst->nlayer); + dprintk(D_RMMC, "dk{%02x %02x %02x %02x %02x}\n", + dvdst->dkey[4+0], dvdst->dkey[4+1], dvdst->dkey[4+2], + dvdst->dkey[4+3], dvdst->dkey[4+4]); + rkey = offlen_rkey(p->auxinfo->auxfile, &len); + if (!rkey) goto end; + dprintk(D_RMMC, "titles %d\n", be32_to_cpu(rkey->ntitle)); + tk = rkey->data; + if (!tk) goto end; + dprintk(D_RMMC, "tk[0]{%02x %02x %02x %02x %02x}\n", + tk->tk[0], tk->tk[1], tk->tk[2], tk->tk[3], tk->tk[4]); + } +#endif + + res = 0; + spin_lock(&auxinfo_lock); + list_add_tail(&p->auxinfo->list, &auxinfo_list); + spin_unlock(&auxinfo_lock); + end: + up(&auxinfo_sema); + if (res) eprintk("%s failed %d\n", auxpath, res); + return res; +} + +// copied and modifed from fileio_attach(). +extern void gen_scsiid(struct iet_volume *volume, struct inode *inode); +int rmmcio_attach(struct iet_volume *lu, char *path) +{ + int res; + struct rmmcio_volume *p; + struct file *filp = NULL; + mm_segment_t oldfs; + struct inode *inode; + void *label = &&err; + char *q; + + if (strncmp(path, "Path=", 5) == 0) + path += 5; + q = path; + while (q && *q) { + if (*q == ',') { + *q = 0; + break; + } + q++; + } + dprintk(D_RMMC, "path %s\n", path); + if (lu->private) { + printk("already attached ? %d\n", lu->lun); + return -EBUSY; + } + + res = -ENOMEM; + p = kmalloc(sizeof(*p), GFP_KERNEL); + if (!p) goto *label; + //dprintk(D_RMMC, "rmmc vol %p\n", p); + label = &&err1; + p->fileio_data = kmalloc(sizeof(*p->fileio_data), GFP_KERNEL); + if (!p->fileio_data) goto *label; + //dprintk(D_RMMC, "fileio_data %p\n", p->fileio_data); + label = &&err2; + p->fileio_data->path = kmalloc(strlen(path) + 1, GFP_KERNEL); + if (!p->fileio_data->path) goto *label; + strcpy(p->fileio_data->path, path); + //dprintk(D_RMMC, "fileio_data->path %p\n", p->fileio_data->path); + label = &&err3; + + oldfs = get_fs(); + set_fs(get_ds()); + filp = filp_open(path, O_RDONLY|O_LARGEFILE, 0); + set_fs(oldfs); + if (IS_ERR(filp)) { + res = PTR_ERR(filp); + eprintk("We can't open %s %d\n", path, res); + goto *label; + } + p->fileio_data->filp = filp; + label = &&err4; + + inode = filp->f_dentry->d_inode; + gen_scsiid(lu, inode); + if (S_ISREG(inode->i_mode)) { + /* nothing to do */ + } else if (S_ISBLK(inode->i_mode)) { + inode = inode->i_bdev->bd_inode; + } else { + eprintk("%s is not a block file %x\n", path, inode->i_mode); + res = -EINVAL; + goto *label; + } + + //dprintk(D_RMMC, "i_size %Lu\n", inode->i_size); + p->auxinfo = NULL; + res = getauxinfo(p); + if (res) goto *label; + +#if 1 + lu->target->trgt_param.target_type = rmmc_ops.id; + //lu->target->trgt_param.wthreads = 1; + //eprintk("%d\n", lu->target->trgt_param.wthreads); +#endif + + lu->blk_shift = RmmcBlkShift; + lu->blk_cnt = inode->i_size >> lu->blk_shift; + lu->private = p; + return 0; + + err4: + filp_close(filp, NULL); + err3: + kfree(p->fileio_data->path); + err2: + kfree(p->fileio_data); + err1: + kfree(p); + err: + eprintk("%s\n", "failed"); + return res; +} + +void +rmmcio_detach(struct iet_volume *lu) +{ + struct rmmcio_volume *p; + struct iet_volume tmp_lu; + + p = lu->private; + auxinfo_unref(p->auxinfo); + memcpy(&tmp_lu, lu, sizeof(lu)); + tmp_lu.private = p->fileio_data; + fileio.detach(&tmp_lu); + //dprintk(D_RMMC, "detached fileio %p{%p}\n", p->fileio_data, p->fileio_data->path); + kfree(p); + //dprintk(D_RMMC, "freed rmmcio vol %p\n", p); + lu->private = NULL; +} + +int +rmmcio_make_request(struct iet_volume *lu, struct tio *tio, int rw) +{ + struct rmmcio_volume *p; + struct iet_volume tmp_lu; + + if (rw != READ) return -EACCES; + p = lu->private; + memcpy(&tmp_lu, lu, sizeof(lu)); // ng. slow. + tmp_lu.private = p->fileio_data; + //dprintk(D_RMMC, "task state %08lx\n", current->state); + return fileio.make_request(&tmp_lu, tio, READ); +} + +int +rmmcio_sync(struct iet_volume *lu, struct tio *tio) +{ + BUG(); + return -1; +} + +#if 0 +u32 +fileio_seek(struct iet_volume *lu, u32 pos) +{ + struct fileio_data *p = (struct fileio_data *)lu->private; + struct file *filp; + assert(p); + filp = p->filp; + return vfs_llseek(filp, pos, 0); +} +#endif + +void +rmmcio_show(struct iet_volume *lu, struct seq_file *seq) +{ + struct rmmcio_volume *p; + struct iet_volume tmp_lu; + + p = lu->private; + seq_printf(seq, " auxref: %d", atomic_read(&p->auxinfo->ref)); + memcpy(&tmp_lu, lu, sizeof(lu)); + tmp_lu.private = p->fileio_data; + fileio.show(&tmp_lu, seq); +} + +struct iotype rmmcio = +{ + .name = "rmmcio", + .attach = rmmcio_attach, + .make_request = rmmcio_make_request, + .sync = rmmcio_sync, + .detach = rmmcio_detach, + .show = rmmcio_show, + //.seek = fileio_seek +}; + +MODULE_AUTHOR("Junjiro Okajima"); +MODULE_DESCRIPTION("iSCSI Target file I/O for read-only/reduced mmc"); +MODULE_LICENSE("GPL"); Index: iet-0.4.8/kernel/rmmc-io.h diff -u /dev/null iet-0.4.8/kernel/rmmc-io.h:1.4 --- /dev/null Fri Jun 3 11:12:25 2005 +++ iet-0.4.8/kernel/rmmc-io.h Tue May 31 20:14:47 2005 @@ -0,0 +1,131 @@ + +#ifndef rmmc_io_h +#define rmmc_io_h + +static char rmmc_io__h[] __attribute__((unused, nocommon)) += "@(#) $Id: rmmc-io.h,v 1.4 2005/05/31 11:14:47 jro Exp $"; // " " __DATE__ " " __TIME__ + +#include "file-io.h" +#include "rmmc_aux.h" + +#define RmmcBlkShift 11 +#define RmmcBlkSize (1<auxinfo; + //if (!auxinfo) return NULL; + return auxinfo->auxfile; +} + +/* ---------------------------------------------------------------------- */ +#include "css-auth.h" + +#define CSSKey1Len 5 +#define CSSKey2Len 5 +struct rmmc_css { + u8 authed; + + u8 agid; + u8 variant; + u8 chal[10]; + struct block bkey1, bkey2, bbuskey; +}; + +static inline void +swap(unsigned char a[], int i, int j) {unsigned char c; c = a[i]; a[i] = a[j]; a[j] = c;} +static inline void +rev5(unsigned char a[]) {swap(a, 0, 4); swap(a, 1, 3);} +static inline void +rev10(unsigned char a[]) {int i; for (i = 0; i < 5; i++) swap(a, i, 9-i);} + +static inline u8* +genbuskey(struct rmmc_css css[]) +{ + rev5(css->bkey1.b); + rev5(css->bkey2.b); + memcpy(css->chal, css->bkey1.b, sizeof(css->bkey1.b)); + memcpy(css->chal+sizeof(css->bkey1.b), css->bkey2.b, sizeof(css->bkey2.b)); + CryptBusKey(css->variant, css->chal, &css->bbuskey); + return css->bbuskey.b; +} + +static inline u8* +genkey1(struct rmmc_css css[]) +{ + rev10(css->chal); + CryptKey1(css->variant, css->chal, &css->bkey1); + rev5(css->bkey1.b); + return css->bkey1.b; +} + +static inline u8* +genkey2(struct rmmc_css css[]) +{ + rev10(css->chal); + CryptKey2(css->variant, css->chal, &css->bkey2); + rev5(css->bkey2.b); + return css->bkey2.b; +} + +static inline int +memcmpkey2(struct rmmc_css css[], u8 a[]) +{ + return memcmp(a, css->bkey2.b, sizeof(css->bkey2.b)); +} + +static inline void +encbybuskey(u8 dst[], u8 src[], u32 len, struct rmmc_css css[]) +{ + u32 i; + for (i = 0; i < len; i++) + dst[i] = src[i] ^ css->bbuskey.b[4-(i%5)]; +} + +/* ---------------------------------------------------------------------- */ +struct rmmc_conn { + int lasttk; + struct rmmc_css css; + int media_event; + + /* statistics */ + struct { + unsigned long read, sendfile; + } readstat; +}; + +static inline struct rmmc_css* +conn_css(struct rmmc_conn conn[]) +{ + //if (!conn) return NULL; + return &conn->css; +} + +static inline struct rmmc_css* +cmnd_css(struct iscsi_cmnd cmnd[]) +{ + struct iscsi_conn *conn; + + //if (!cmnd) return NULL; + conn = cmnd->conn; + //if (!conn) return NULL; + return conn_css(conn->private); +} + +#endif //rmmc_io_h Index: iet-0.4.8/kernel/scsiop.h diff -u /dev/null iet-0.4.8/kernel/scsiop.h:1.1 --- /dev/null Fri Jun 3 11:12:25 2005 +++ iet-0.4.8/kernel/scsiop.h Tue May 31 13:59:35 2005 @@ -0,0 +1,35 @@ + +#ifndef scsiop_h +#define scsiop_h + +static char scsiop__h[] __attribute__((unused, nocommon)) += "@(#) $Id: scsiop.h,v 1.1 2005/05/31 04:59:35 jro Exp $"; // " " __DATE__ " " __TIME__ + +#include +#include + +static inline char* +opstr(unsigned int op) +{ + switch (op) { + case TEST_UNIT_READY: return "TEST_UNIT_READY"; + case REPORT_LUNS: return "REPORT_LUNS"; + case INQUIRY: return "INQUIRY"; + case READ_CAPACITY: return "READ_CAPACITY"; + case GPCMD_MODE_SENSE_10: return "GPCMD_MODE_SENSE_10"; + case GPCMD_READ_TOC_PMA_ATIP: return "GPCMD_READ_TOC_PMA_ATIP"; + case READ_10: return "READ_10"; + case GPCMD_REPORT_KEY: return "GPCMD_REPORT_KEY"; + case GPCMD_READ_DVD_STRUCTURE: return "GPCMD_READ_DVD_STRUCTURE"; + case GPCMD_SEND_KEY: return "GPCMD_SEND_KEY"; + case GPCMD_READ_DISC_INFO: return "GPCMD_READ_DISC_INFO"; + case GPCMD_READ_SUBCHANNEL: return "GPCMD_READ_SUBCHANNEL"; + case GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL: return "GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL"; + case GPCMD_READ_TRACK_RZONE_INFO: return "GPCMD_READ_TRACK_RZONE_INFO"; + case GPCMD_GET_EVENT_STATUS_NOTIFICATION: return "GPCMD_GET_EVENT_STATUS_NOTIFICATION"; + case GPCMD_GET_CONFIGURATION: return "GPCMD_GET_CONFIGURATION"; + } + return "unknown"; +} + +#endif //scsiop_h Index: iet-0.4.8/kernel/target_disk.c diff -u iet-0.4.8/kernel/target_disk.c:1.1.1.1 iet-0.4.8/kernel/target_disk.c:1.5 --- iet-0.4.8/kernel/target_disk.c:1.1.1.1 Tue May 24 12:46:19 2005 +++ iet-0.4.8/kernel/target_disk.c Tue May 31 13:59:35 2005 @@ -11,6 +11,7 @@ #include "iscsi.h" #include "iscsi_dbg.h" +#include "file-io.h" static int insert_disconnect_pg(u8 *ptr) { @@ -354,6 +355,7 @@ struct iscsi_scsi_cmd_hdr *req = cmnd_hdr(cmnd); req->opcode &= ISCSI_OPCODE_MASK; + if (req->scb[0]) dprintk(D_RMMC, "op %02x\n", req->scb[0]); switch (req->scb[0]) { case INQUIRY: Index: iet-0.4.8/kernel/target_rmmc.c diff -u /dev/null iet-0.4.8/kernel/target_rmmc.c:1.12 --- /dev/null Fri Jun 3 11:12:25 2005 +++ iet-0.4.8/kernel/target_rmmc.c Thu Jun 2 16:22:06 2005 @@ -0,0 +1,1356 @@ +/* + * (C) 2004-2005 Junjiro Okajima + * This code is licenced under the GPL. + * + * heavily based on code from *.c under kernel sub directory, which were,,, + * Copyright (C) 2004 Fujita Tomonori + * licensed under the terms of the GPL. + */ + +static char target_rmmc_c[] __attribute__((unused, nocommon)) += "@(#) $Id: target_rmmc.c,v 1.12 2005/06/02 07:22:06 jro Exp $"; // " " __DATE__ " " __TIME__ + +#include +#include +#include +#include +#include + +#include "iscsi.h" +#include "iscsi_dbg.h" +#include "rmmc-io.h" +#include "scsiop.h" + +static int +rmmc_inquiry(struct iscsi_cmnd *cmnd) +{ + struct iscsi_scsi_cmd_hdr *req = cmnd_hdr(cmnd); + struct tio *tio; + int len; + u8 *data; + u8 *scb = req->scb, evpd; + struct rmmc_css *css; + + evpd = scb[1]&0x01; +#if 0 + dprintk(D_RMMC, "evpd %d, page code %02x, al-len %02x %02x, ctrl %02x\n", + evpd, scb[2], scb[3], scb[4], scb[5]); + //dprintk(D_RMMC, "req->data_len %u\n", be32_to_cpu(req->data_length)); +#endif + + if (evpd) return -1; // tmp + + css = cmnd_css(cmnd); + //if (!css) return -1; + css->authed = 0; // tmp + //dprintk(D_RMMC, "authed %d\n", css->authed); + +#if 0 + { + int ret = disk_ops.execute_cmnd(cmnd); + if (ret) return ret; + } + tio = cmnd->tio; +#else + tio = cmnd->tio = tio_alloc(1); +#endif + data = page_address(tio->pvec[0]); + //assert(data); + len = 36; + memset(data, 0, len); + + data[0] = TYPE_ROM; // cd or dvd + if (!cmnd->lun) data[0] = TYPE_NO_LUN; + data[1] = 0x80; // rmb + //data[2] = 0x05; // scsi version + data[3] = 0x02; // norm_aca = 0, hisup = 0, data format(mmc) + //data[5] = 0x40; // sccs = 0, acc = 0, tpgs = 0, 3pc = 0, prot = 0 + //data[6] = 0x80; // bque = 1, encserv = 0, vs = ?, multip = 0, mchnager = 0 + //data[7] = 0; // sync = ?, linked = 0, cmdq = 0, vs = ? + memcpy(data + 8, "LINUX ", 8); + memcpy(data + 16, "ISCSI ", 16); + memcpy(data + 32, "0 ", 4); +#if 0 + data[58] = 0x04; // version descriptor mmc-5 + data[59] = 0x20; + data[60] = 0x09; // iscsi + data[61] = 0x60; + data[62] = 0x03; // spc-3 + data[63] = 0x00; + len = 64; +#endif +#if 0 + if (evpd) { + data[0] |= TYPE_ROM; // cd or dvd(spc-3) + + /* EVPD bit set */ + if (scb[2] == 0x0) { + data[1] = 0x0; + data[3] = 3; data[3] = 2; // 0x00 and 0x83 + data[4] = 0x0; + data[5] = 0x80; data[5] = 0x83; // hide 0x80 + data[6] = 0x83; + tio->size = 7; tio->size = 6; // hide 0x80 + } else if (scb[2] == 0x80) { + // hide it + data[1] = 0x80; + data[3] = 4; + memset(data + 4, 0x20, 4); + tio->size = 8; + } else if (scb[2] == 0x83) { + // Device Identification VPD page + data[1] = 0x83; + data[3] = 12; + data[4] = 0x2; + data[5] = 0x2; + data[7] = 8; + *((u32 *) (data + 8)) = cmnd->conn->session->target->tid; + *((u32 *) (data + 12)) = cmnd->lun ? cmnd->lun->lun : 0; + tio->size = 16; + } + } +#endif + + tio_set(tio, min_t(u16, len, getu16(scb+3)), 0); + data[4] = len-4; + + return 0; +} + +static int +rmmc_capacity(struct iscsi_cmnd *cmnd) +{ + struct tio *tio; + u32 *data32; + struct iet_volume *lun; + + lun = cmnd->lun; + //if (!lun) return -1; + + tio = cmnd->tio = tio_alloc(1); + data32 = page_address(tio->pvec[0]); + //assert(data32); + data32[0] = cpu_to_be32(lun->blk_cnt - 1); + data32[1] = cpu_to_be32(RmmcBlkSize); + //dprintk(D_RMMC, "data{%u, %u}\n", be32_to_cpu(data[0]), be32_to_cpu(data[1])); + + tio_set(tio, 8, 0); + + return 0; +} + +static int +rmmc_mode_sense10(struct iscsi_cmnd *cmnd) +{ + struct iscsi_scsi_cmd_hdr *req = cmnd_hdr(cmnd); + struct tio *tio; + u8 *data, *scb = req->scb, *p; + int len = 8; + u8 llbaa, dbd, pc, pgcd, subpgcd; + + llbaa = (scb[1]>>4)&1; + dbd = (scb[1]>>3)&1; + pc = scb[2]>>6; + pgcd = scb[2]&0x3f; + subpgcd = scb[3]; +#if 0 + dprintk(D_RMMC, "llbaa %d, dbd %d, pc %01x, page code %02x, sub page code %02x, " + "al-len %02x %02x, ctrl %02x\n", + llbaa, dbd, pc, pgcd, subpgcd, + scb[7], scb[8], scb[9]); +#endif + + switch (pgcd) { + case GPMODE_CAPABILITIES_PAGE: + //dprintk(D_RMMC, "%s\n", "CAPABILITIES"); + tio = cmnd->tio = tio_alloc(1); + data = page_address(tio->pvec[0]); + //assert(data); + len += 28; // 24 + memset(data, 0, len); + p = data+8; + p[0] = pgcd; // ps = 0 + //p[0] = 0x80 | pgcd; // ps = 1 + p[1] = 28; // len + p[2] = 0x08; // dvd-rom + //p[2] = 0x3f; // read all dvd + //p[4] = 1; // audio-play + p[23] = 1; // css/cprm + break; + case GPMODE_AUDIO_CTL_PAGE: + //dprintk(D_RMMC, "%s\n", "AUDIO_CTL"); + return -1; + + //data[2] = TYPE_ROM; // cd or dvd + //data[3] = 0?; // device specific + //data[4] = 0?; // long lba + //if (dbd) data[7] = 0; // block desc. len + p[0] = pgcd; // ps = 0 + p[1] = 0x0e; // len + p[2] = 0x40; // immed = 1, sotc = 0 + len += 0x0e; + break; +#if 0 + case 0x0: + break; + case 0x2: + len += insert_disconnect_pg(data + len); + break; + case 0x3: + len += insert_format_m_pg(data + len); + break; + case 0x4: + len += insert_geo_m_pg(data + len, cmnd->lun->blk_cnt); + break; + case 0x8: + len += insert_caching_pg(data + len); + break; + case 0xa: + len += insert_ctrl_m_pg(data + len); + break; + case 0x1c: + len += insert_iec_m_pg(data + len); + break; + case 0x3f: + len += insert_disconnect_pg(data + len); + len += insert_format_m_pg(data + len); + len += insert_geo_m_pg(data + len, cmnd->lun->blk_cnt); + len += insert_caching_pg(data + len); + len += insert_ctrl_m_pg(data + len); + len += insert_iec_m_pg(data + len); + break; +#endif + default: + dprintk(D_RMMC, "un-implemented page code %02x\n", pgcd); + return -1; + } + + tio_set(tio, min_t(u16, len, getu16(scb+7)), 0); + putu16(data, len-2); + + return 0; +} + +static int +rmmc_tpa(struct iscsi_cmnd *cmnd) +{ + struct iscsi_scsi_cmd_hdr *req = cmnd_hdr(cmnd); + struct tio *tio; + u8 *data, len = 0, fmt, msf; + u8 *scb = req->scb; + struct iet_volume *lun; + + msf = (scb[1]>>1)&1; + fmt = scb[2]&0x0f; +#if 0 + dprintk(D_RMMC, "time %d, format %x, tr/sess-num %02x, " + "al-len %02x %02x, ctrl %02x\n", + msf, fmt, scb[6], + scb[7], scb[8], scb[9]); +#endif + + lun = cmnd->lun; + //if (!lun) return -1; + tio = cmnd->tio = tio_alloc(1); + data = page_address(tio->pvec[0]); + //assert(data); + + switch (fmt) { + case 0: + len = 20; + memset(data, 0, len); + data[1] = 0x12; + data[2] = data[3] = data[6] = 1; + data[5] = data[13] = 0x14; + if (msf) putu32(data+8, 0x00000200); + data[14] = 0xaa; + if (msf) putu32(data+16, 0x00ff3b4a); + else putu32(data+16, lun->blk_cnt); + break; + case 1: + len = 12; + memset(data, 0, len); + data[1] = 0x0a; + data[2] = data[3] = data[6] = 1; + data[5] = 0x14; + if (msf) putu32(data+8, 0x00000200); + break; + default: + dprintk(D_RMMC, "Not Implemented Format 0x%02x\n", fmt); + return -1; + } + + tio_set(tio, min_t(u16, len, getu16(scb+7)), 0); + //return -1*(int)(jiffies&1); + return 0; +} + +/* ---------------------------------------------------------------------- */ +static inline struct rmmc_aux_tk* +findtk(struct rmmc_conn mconn[], struct rmmc_aux_rkey rkey[], u32 lba) +{ + struct rmmc_aux_tk *tk, *o; + int n, old; + + o = rkey->data; + n = be32_to_cpu(rkey->ntitle); + old = mconn->lasttk; + + tk = o+mconn->lasttk; + for (; mconn->lasttk < n; mconn->lasttk++, tk++) + if (be32_to_cpu(tk->lba[0]) <= lba + && lba <= be32_to_cpu(tk->lba[1])) + return tk; + + mconn->lasttk = 0; + tk = o; + for (; mconn->lasttk < old; mconn->lasttk++, tk++) + if (be32_to_cpu(tk->lba[0]) <= lba + && lba <= be32_to_cpu(tk->lba[1])) + return tk; + + return NULL; +} + +/* ---------------------------------------------------------------------- */ +static inline int +isencrypted(u8 *a, u32 size, int do_warn) +{ + if (a[0x14] & 0x30) goto end; + //if (a[0x14] & 0x10) goto end; + if (size <= RmmcBlkSize) return 0; + a += RmmcBlkSize; + if (a[0x14] & 0x30) goto end; + //if (a[0x14] & 0x10) goto end; + return 0; + end: + if (do_warn) + eprintk("%s\n", "encrypted blk is going to be read without the authentication"); + return 1; +} + +static inline int +rmmc_readpages(struct iscsi_cmnd cmnd[], int need_auth) +{ + struct tio *tio = cmnd->tio; + int i, ret; + u32 size; + struct page *page; + + tio_add_pages(tio, tio->need_pages); + ret = tio_read(cmnd->lun, tio); + if (ret) { + dprintk(D_RMMC, "%s\n", "read error"); + //cmnd->lun->dev_status = -1; + return -1; + } + if (!need_auth) return 0; + + for (size = tio->size, i = 0; i < tio->pg_cnt; i++, size -= PAGE_SIZE) { + u8 *p; + page = tio->pvec[i]; + //assert(page); +#if 0 + if (PageError(page) || !PageUptodate(page)) + return -1; +#endif + p = page_address(page); + //assert(p); + if (isencrypted(p, size, 1)) + return -1; + } + return 0; +} + +struct rmmc_send_desc { + struct tio *tio; + int i; + int need_auth; + int encrypted; +}; + +static int +rmmc_send_actor(read_descriptor_t *desc, struct page *page, + unsigned long offset, unsigned long size) +{ + unsigned long count = desc->count; + struct rmmc_send_desc *a = desc->arg.data; + struct tio *tio = a->tio; + + //dprintk(D_RMMC, "size %lu, count %lu\n", size, count); + if (size > count) size = count; + tio->pvec[a->i++] = page; + if (a->need_auth && !a->encrypted) { + //assert(page); + u8 *p = page_address(page); + //assert(p); + if (isencrypted(p, size, 1)) a->encrypted++; + } + desc->count = count - size; + desc->written += size; + return size; +} + +static int +rmmc_read(struct iscsi_cmnd *cmnd) +{ + struct tio *tio = cmnd->tio; + struct iet_volume *lun; + struct rmmcio_volume *vol; + struct fileio_data *fileio_data; + struct file *filp; + struct rmmc_send_desc a; + ssize_t written, retval; + loff_t offset; + int count, ret, need_auth; + struct iscsi_conn *conn; + struct rmmc_conn *mconn; + struct rmmc_css *css; + int ddigest; + +#if 0 + struct iscsi_scsi_cmd_hdr *req = cmnd_hdr(cmnd); + u8 *scb = req->scb; + dprintk(D_RMMC, "op %02x, dpo %d, fua %d, reladr %d, " + "blk{%02x %02x %02x %02x}, " + "len{%02x %02x}, ctrl %02x\n", + scb[0], (scb[1]&0x10)>>4, (scb[1]&0x08)>>3, scb[1]&0x01, + scb[2], scb[3], scb[4], scb[5], + scb[7], scb[8], scb[9]); + dprintk(D_RMMC, "idx %lu, pg_cnt %u, offset %u, size %u\n", + tio->idx, tio->pg_cnt, tio->offset, tio->size); +#endif + + ret = -1; + lun = cmnd->lun; + //if (!lun) goto err; +#if 0 + if (lun->dev_status) { + dprintk(D_RMMC, "%s\n", "un-recovered error(yet)"); + goto err; + } +#endif + conn = cmnd->conn; + //if (!conn) goto err; + mconn = conn->private; + //if (!mconn) goto err; + css = &mconn->css; + //if (!css) goto err; + need_auth = !css->authed; + +#if 0 + // i could not distinguish the legal player or illegal ripper after the player. + dprintk(D_RMMC, "conn{cid %x, state %lx, stat_sn %x, exp_stat_sn %x}\n", + conn->cid, conn->state, conn->stat_sn, conn->exp_stat_sn); +#endif + + offset = tio->offset; + offset += (loff_t) tio->idx << PAGE_CACHE_SHIFT; + //dprintk(D_RMMC, "offset %Lu, size %d\n", offset>>RmmcBlkShift, tio->size); + + vol = lun->private; + //if (!vol) goto err; + if (need_auth) { + struct rmmc_aux_file *aux; + struct rmmc_aux_rkey *rkey; + u32 len; + + aux = vol_auxfile(vol); + //if (!aux) return -1; + rkey = offlen_rkey(aux, &len); + //if (!rkey) return -1; + if (need_auth) + need_auth = findtk(mconn, rkey, offset>>RmmcBlkShift) != NULL; + } + fileio_data = vol->fileio_data; + //if (!fileio_data) goto err; + filp = fileio_data->filp; + //if (!filp) goto err; + if (/* !(conn->ddigest_type & DIGEST_NONE) + || */!filp->f_op->sendfile) + return rmmc_readpages(cmnd, need_auth); + + retval = rw_verify_area(READ, filp, &offset, tio->size); + if (retval) goto err; + retval = security_file_permission (filp, MAY_READ); + if (retval) goto err; + + count = tio->need_pages*sizeof(struct page*); + tio->pvec = kmalloc(count, GFP_KERNEL); + if (!tio->pvec) goto err; + memset(tio->pvec, 0, count); + + a.tio = tio; + a.i = 0; + a.need_auth = need_auth; + a.encrypted = 0; + written = filp->f_op->sendfile(filp, &offset, tio->size, + rmmc_send_actor, &a); + if ((need_auth && a.encrypted) || written != tio->size) { + kfree(tio->pvec); + tio->pvec = NULL; + goto err; + } + ret = 0; + err: + tio->pg_cnt = 0; + //memset(tio->pvec, 0, count); + + return ret; +} + +static int +rmmc_tur(struct iscsi_cmnd *cmnd) +{ + struct iet_volume *lun; + struct rmmcio_volume *vol; + struct fileio_data *fio; + struct file *filp; + struct dentry *dent; + struct inode *inode; + struct block_device *bdev; + struct gendisk *gdk; + struct super_block *sb; + + return 0; + + lun = cmnd->lun; + //dprintk(D_RMMC, "lun->dev_status %d\n", lun->dev_status); + //if (!lun->dev_status) return 0; // device is fine. + + vol = lun->private; + fio = vol->fileio_data; + filp = fio->filp; + dent = filp->f_dentry; + inode = dent->d_inode; + bdev = inode->i_bdev; + sb = dent->d_sb; + bdev = sb->s_bdev; + //dprintk(D_RMMC, "lun->dev %08x\n", lun->dev); + //dprintk(D_RMMC, "filp->f_error %08x\n", filp->f_error); + //dprintk(D_RMMC, "bdev %p\n", bdev); + if (0 && bdev) { + dprintk(D_RMMC, "bdev->bd_invalidated %08x\n", bdev->bd_invalidated); + gdk = bdev->bd_disk; + //dprintk(D_RMMC, "gdk %p\n", gdk); + if (gdk) dprintk(D_RMMC, "gdk->flags %08x\n", gdk->flags); + } + return 0; +} + +/* ---------------------------------------------------------------------- */ + +static int +rmmc_dvdst(struct iscsi_cmnd *cmnd) +{ + struct iscsi_scsi_cmd_hdr *req = cmnd_hdr(cmnd); + struct tio *tio; + u8 *data, agid, num; + u8 *scb = req->scb; + struct iet_volume *lun; + struct rmmc_aux_file *aux; + struct rmmc_aux_dvdst *dvdst; + struct rmmc_aux_layer *layer; + struct rmmc_aux_phys *phys; + struct rmmc_aux_cprt *cprt; + u8 *manuf; + struct rmmc_css *css; + u32 len; + enum {Phys, Cprt, DKey, + Burst_Cutting_Area, + Manufacturing, + Cprt_Management, + Media_Identifier, + Media_Key, + ADIP = 0x11, + Disc_Control = 0x30, + READ_SEND_DVD_STRUCTURE = 0xff}; + + agid = scb[10]>>6; + num = scb[6]; +#if 0 + dprintk(D_RMMC, "addr{%02x %02x %02x %02x}, layer %d, format %x, " + "al-len %02x %02x, agid %x, ctrl %02x\n", + scb[2], scb[3], scb[4], scb[5], num, scb[7], + scb[8], scb[9], agid, scb[11]); +#endif + + lun = cmnd->lun; + //if (!lun) return -1; + aux = vol_auxfile(lun->private); + if (!aux) return -1; + dvdst = offlen_dvdst(aux, &len); + if (!dvdst) return -1; + layer = offlen_layer(dvdst, num, &len); + if (!layer) return -1; + + tio = cmnd->tio = tio_alloc(1); + data = page_address(tio->pvec[0]); + //assert(data); + + switch (scb[7]) { + case Phys: + //dprintk(D_RMMC, "phys%s", "\n"); + phys = offlen_phys(layer, &len); + if (!phys) return -1; + memcpy(data, phys, len); + break; + case Cprt: + //dprintk(D_RMMC, "copyright%s", "\n"); + cprt = offlen_cprt(layer, &len); + if (!cprt) return -1; + memcpy(data, cprt, len); + break; + case DKey: + //dprintk(D_RMMC, "disc key%s", "\n"); + css = cmnd_css(cmnd); + //if (!css) return -1; + if (!css->authed) return -1; + len = sizeof(dvdst->dkey); + memcpy(data, dvdst->dkey, 4); + encbybuskey(data+4, dvdst->dkey+4, len-4, css); + break; + case Manufacturing: + dprintk(D_RMMC, "manufacturing%s", "\n"); + manuf = offlen_manuf(layer, &len); + if (!manuf) return -1; + memcpy(data, manuf, len); + break; + default: + dprintk(D_RMMC, "unknown %02x\n", scb[7]); + return -1; + } + + tio_set(tio, min_t(u16, len, getu16(scb+8)), 0); + return 0; +} + +static int +rmmc_report_key(struct iscsi_cmnd *cmnd) +{ + struct iscsi_scsi_cmd_hdr *req = cmnd_hdr(cmnd); + struct tio *tio; + u8 *data, len = 4, *p, agid, fmt, class; + u8 *scb = req->scb; + struct iscsi_conn *conn; + struct rmmc_conn *mconn; + struct rmmc_css *css; + struct iet_volume *lun; + struct rmmc_aux_file *aux; + struct rmmc_aux_rkey *rkey; + struct rmmc_aux_tk *tk; + u32 len32, lba; + enum {Agid_CSS_CPPM, ChalKey, Key1, + TitleKey = 0x04, + ASF, + RPCState = 0x08, + AGID_CPRM = 0x11, + None = 0x3f}; + + fmt = scb[10]&0x3f; + class = scb[7]; + agid = scb[10]>>6; + + switch (class) { + case 0x00: // CSS/CPPM/CPRM Key Class + break; + default: + dprintk(D_RMMC, "Not Implemented keyclass 0x%02x\n", scb[7]); + return -1; + } + +#if 0 + dprintk(D_RMMC, "CSS/CPPM/CPRM Key Class, addr{%02x %02x %02x %02x}, " + "agid %01x, format %02x, " + "al-len %02x %02x, ctrl %02x\n", + scb[2], scb[3], scb[4], scb[5], + agid, scb[10]&0x3f, + scb[8], scb[9], scb[11]); +#endif + + conn = cmnd->conn; + //if (!conn) return -1; + mconn = conn->private; + //if (!mconn) return -1; + css = &mconn->css; + //if (!css) return -1; + + tio = cmnd->tio = tio_alloc(1); + data = page_address(tio->pvec[0]); + //assert(data); + p = data+4; + + switch (fmt) { + case RPCState: + len += 4; + memset(data, 0, len); + p[0] = 0xc0; // type = 11h, vra = 0, ucca = 0 + p[1] = 0xfd; // region mask + p[2] = 0x01; // rpc scheme + break; + case None: + len = 0; + //css->authed = 0; + //dprintk(D_RMMC, "authed %d\n", css->authed); + break; + case Agid_CSS_CPPM: + len += 4; + memset(data, 0, len); + p[3] = css->agid<<6; + break; + case Key1: + len += 8; + memcpy(p, genkey1(css), CSSKey1Len); + break; + case ChalKey: + len += 12; + get_random_bytes(css->chal, sizeof(css->chal)); + memcpy(p, css->chal, sizeof(css->chal)); + break; + case ASF: + len += 4; + memset(data, 0, len); + p[3] = css->authed; + break; + case TitleKey: + if (!css->authed || css->agid != agid) return -1; + lun = cmnd->lun; + //if (!lun) return -1; + aux = vol_auxfile(lun->private); + if (!aux) return -1; + rkey = offlen_rkey(aux, &len32); + if (!rkey) return -1; + lba = getu32(scb+2); + //dprintk(D_RMMC, "title key lba=%u\n", lba); + tk = findtk(mconn, rkey, lba); + if (!tk) return -1; + + len += 8; + memset(data, 0, len); + p[0] = tk->cpbits; + encbybuskey(p+1, tk->tk, sizeof(tk->tk), css); + break; + default: + dprintk(D_RMMC, "Not Implemented fmt 0x%02x\n", fmt); + return -1; + } + + if (len) putu16(data, len-2); + tio_set(tio, min_t(u16, len, getu16(scb+8)), 0); +#if 0 + dprintk(D_RMMC, "res{%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x}\n", + data[0], data[1], data[2], data[3], data[4], + data[5], data[6], data[7], data[8], data[9]); +#endif + return 0; +} + +static int +rmmc_send_key(struct iscsi_cmnd *cmnd) +{ + struct iscsi_scsi_cmd_hdr *req = cmnd_hdr(cmnd); + struct tio *tio = cmnd->tio; + u8 *data, len, *p; + u8 *scb = req->scb, kcls, kfmt, agid; + struct rmmc_css *css; + + list_del_init(&cmnd->list); //?? + kcls = scb[7]; +#if 0 + dprintk(D_RMMC, "key-class %02x, len{%02x %02x}, ctrl %02x\n", + kcls, scb[8], scb[9], scb[11]); + dprintk(D_RMMC, "tio %p\n", tio); + if (tio) { + dprintk(D_RMMC, "tio{pg_cnt %d, pvec %p}\n", tio->pg_cnt, tio->pvec); + if (cmnd->req) tio = cmnd->req->tio; + if (tio) + dprintk(D_RMMC, "cmnd->req->tio{pg_cnt %d, pvec %p}\n", + tio->pg_cnt, tio->pvec); + } +#endif + + if (kcls) { + dprintk(D_RMMC, "Not Implemented key-class 0x%02x\n", kcls); + return -1; + } + + // DVD CSS/CPPM or CPRM + kfmt = scb[10]&0x3f; + agid = scb[10]>>6; + //dprintk(D_RMMC, "agid %x, format %02x\n", agid, kfmt); + + css = cmnd_css(cmnd); + //if (!css) return -1; + + switch (kfmt) { + case 0x01: // challenge key + case 0x03: // key 2 + css->authed = 0; + //dprintk(D_RMMC, "authed %d\n", css->authed); + break; + case 0x3f: // invalidate agid + //dprintk(D_RMMC, "%s\n", "invalidate agid"); + return 0; + case 0x06: // rpc struct + //dprintk(D_RMMC, "rpc struct{region %02x}\n", scb[4]); + return 0; + default: + dprintk(D_RMMC, "Not Implemented key-format 0x%02x\n", kfmt); + return -1; + } + + if (!tio || !tio->pvec || !tio->pvec[0]) { + eprintk("%s\n", "no tio or tio->pvec"); + return -1; + } + data = page_address(tio->pvec[0]); + assert(data); + p = data+4; + len = getu16(data); + + switch (kfmt) { + case 0x01: // challenge key + if (len < sizeof(css->chal)+2) return -1; + memcpy(css->chal, p, sizeof(css->chal)); + break; + case 0x03: // key 2 + if (len < CSSKey2Len+2) return -1; + genkey2(css); + css->authed = !memcmpkey2(css, p); + //dprintk(D_RMMC, "css->authed %d\n", css->authed); + if (!css->authed) break; + genbuskey(css); + break; + } + + return 0; +} + +static int +rmmc_discinfo(struct iscsi_cmnd *cmnd) +{ + struct iscsi_scsi_cmd_hdr *req = cmnd_hdr(cmnd); + struct tio *tio; + u8 *data; + u8 *scb = req->scb; + int len; + struct iet_volume *lun; + struct rmmc_aux_file *aux; + struct rmmc_aux_discinfo *discinfo; + + //dprintk(D_RMMC, "al-len{%0x2 %02x}, cntrl %02x\n", scb[7], scb[8], scb[9]); + + lun = cmnd->lun; + //if (!lun) return -1; + aux = vol_auxfile(lun->private); + if (!aux) return -1; + discinfo = offlen_discinfo(aux, &len); + if (!discinfo) return -1; + //dprintk(D_RMMC, "len %d\n", len); + //if (len > PAGE_SIZE) return -1; + + tio = cmnd->tio = tio_alloc(1); + data = page_address(tio->pvec[0]); + //assert(data); + //clear_page(data); + memcpy(data, discinfo, len); + tio_set(tio, min_t(u16, len, getu16(scb+7)), 0); +#if 0 + dprintk(D_RMMC, "len %d\n", len); + dprintk(D_RMMC, "res{%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x}\n", + data[0], data[1], data[2], data[3], data[4], + data[5], data[6], data[7], data[8], data[9]); +#endif + return 0; + +#if 0 + data[1] = 32; + data[2] = 0x0e; // un-erasable, complete session and finalized disc. + data[3] = 1; // Number of First Track on Disc + data[4] = 1; //? Number of Sessions (Least Significant Byte) + data[5] = 1; //? First Track Number in Last Session (Least Significant Byte) + data[6] = 1; //? Last Track Number in Last Session (Least Significant Byte) + // DID_V = 0, DBC_V = 0, URU = 1, DAC_V = 0?, Dbit = 0, BG Format Status = 0 + data[7] = 0x20 ; + data[8] = 0xff; // Disc Type + data[9] = 0; //? Number of Sessions (Most Significant Byte) + data[10] = 0; //? First Track Number in Last Session (Most Significant Byte) + data[11] = 0; //? Last Track Number in Last Session (Most Significant Byte) + // Disc Identification = 0 + // Last Session Lead-in Start Address = 0 + // Last Possible Lead-out Start Address = 0 + // Disc Bar Code = 0? + // Disc Application Code = 0? + // Number of OPC Tables = 0? + res = 0; + + tio_set(tio, min_t(u16, 34, getu16(scb+7)), 0); + + return res; +#endif +} + +//http://www.microsoft.com/whdc/device/storage/GESN_Imp.mspx +static int +rmmc_event(struct iscsi_cmnd *cmnd) +{ + struct iscsi_scsi_cmd_hdr *req = cmnd_hdr(cmnd); + struct tio *tio; + u8 *data; + u8 *scb = req->scb; + int len, polled, class; + struct iscsi_conn *conn; + struct rmmc_conn *mconn; + + polled = scb[1]&1; + class = scb[4]; +#if 0 + dprintk(D_RMMC, "polled %d, class %02x, al-len{%0x2 %02x}, cntrl %02x\n", + polled, class, scb[7], scb[8], scb[9]); +#endif + if (polled != 1) { + dprintk(D_RMMC, "un-supported polled %d\n", polled); + return -1; + } + + tio = cmnd->tio = tio_alloc(1); + data = page_address(tio->pvec[0]); + //assert(data); + len = 4; + + switch (class) { + case 0x02: // op change? + memset(data, 0, len); + data[2] = 0x80; + data[3] = 0x14; //0x04; + break; + case 0x10: // media + len += 4; + memset(data, 0, len); + data[2] = 0x04; + data[3] = 0x14; //0x04; + conn = cmnd->conn; + //if (!conn) return -1; + mconn = conn->private; + //if (!mconn) return -1; + if (!mconn->media_event) { + // first time + data[4] = 0x02; // new media + mconn->media_event = 1; + } else + ;// media never change. + data[5] = 0x02; + break; + default: + dprintk(D_RMMC, "un-supported class %d\n", class); + return -1; + } + + putu16(data, len-2); + tio_set(tio, min_t(u16, len, getu16(scb+7)), 0); + return 0; +} + +static int +rmmc_medium_removal(struct iscsi_cmnd *cmnd) +{ +#if 0 + struct iscsi_scsi_cmd_hdr *req = cmnd_hdr(cmnd); + int persistent, prevent; + u8 *scb = req->scb; + + persistent = scb[4]&2; + prevent = scb[4]&1; + dprintk(D_RMMC, "persistent %d, prevent %d\n", persistent, prevent); +#endif + return 0; +} + +#if 0 +static int +rmmc_track_info(struct iscsi_cmnd *cmnd) +{ + struct iscsi_scsi_cmd_hdr *req = cmnd_hdr(cmnd); + struct tio *tio; + u8 *data; + u8 *scb = req->scb; + int res = -1; + u32 *p32; + + dprintk(D_RMMC, "type %x, addr/num{%02x %02x %02x %02x}, " + "al-len{%0x2 %02x}, cntrl %02x\n", + scb[1]&0x3, scb[2], scb[3], scb[4], scb[5], + scb[7], scb[8], scb[9]); + dprintk(D_RMMC, "%s\n", "stopped"); return -1; + + tio = cmnd->tio = tio_alloc(1); + data = page_address(tio->pvec[0]); + //assert(data); + //clear_page(data); + + data[1] = 40-2; // len + data[2] = 1; // track + data[3] = 1; // session + data[5] = 0x04; // damage = 0, copy = 0, track mode = 0x04 + data[6] = 0xc1; // rt = 1, blank = 0, packet = ?, fp = ?, data mode = 1 + data[7] = 0x02; // lra = 1, nwa = 0 + p32 = (void*)(data+8); + *p32++ = 0;//cpu_to_be32(); // track start addr + *p32++ = 0;//cpu_to_be32(); // next writable + *p32++ = 0;//cpu_to_be32(); // free + *p32++ = 0;//cpu_to_be32(16); // fixed packet size/blocking factor + *p32++ = 0;//cpu_to_be32(); // track size + *p32++ = 0;//cpu_to_be32(); // last recorded + data[32] = 1; // track + data[33] = 1; // session + //data[36] = 0x; // read compatibility + + tio_set(tio, min_t(u16, 40, getu16(scb+7)), 0); + res = 0; + + return res; +} +#endif + +#if 0 +static int +rmmc_get_config(struct iscsi_cmnd *cmnd) +{ + struct iscsi_scsi_cmd_hdr *req = cmnd_hdr(cmnd); + struct tio *tio; + u8 *data; + u8 *scb = req->scb; + int res = -1, len; + u16 feature; + u32 *p32; + u8 *p8, rt; + + rt = scb[1]&0x03; + dprintk(D_RMMC, "rt %x, feature{%02x %02x}, " + "al-len %02x %02x, ctrl %02x\n", + rt, scb[2], scb[3], + scb[7], scb[8], scb[9]); + + tio = cmnd->tio = tio_alloc(1); + data = page_address(tio->pvec[0]); + assert(data); + clear_page(data); + + data[7] = 0x10; // profile, dvd-rom + len = 8; // header + p8 = data; + p8[0] = scb[2]; // feature code + p8[1] = scb[3]; // feature code + if (rt == 2) { + /* The Feature Header and the Feature Descriptor identified by + * Starting Feature Number shall be returned. + * If the Logical Unit does not support the specified feature, + * only the Feature Header shall be returned. + */ + feature = getu16(scb+2); + dprintk(D_RMMC, "feautre %04x\n", feature); + switch (feature) { + case 0x0000: // profile list + dprintk(D_RMMC, "%s\n", "profile list"); + p8[2] = 0x03; // version, presisten, current + p8[3] = 4; // len + p8 += 4; + p8[0] = 0x00; p8[1] = 0x10; // dvd + p8[2] = 1; // currentP + len += 4; + break; + case 0x0108: // Logical Unit Serial Number + dprintk(D_RMMC, "%s\n", "Logical Unit Serial Number"); + p8[2] = 0x03; // presisten, current + p8[3] = 4; // len + p8[4] = 'j'; p8[5] = 'r'; p8[6] = 'o'; p8[7] = 0; + len += 8; + break; + case 0x0106: // dvd-css + dprintk(D_RMMC, "%s\n", "DVD css"); + p8[2] = 0x03; // persisten = 1, current = 1 + p8[3] = 4; // len + p8[7] = 1; // css version + len += 8; + break; + case 0x001F: // DVD Read + dprintk(D_RMMC, "%s\n", "DVD Read"); + p8[2] = 0x03; // persisten = 1, current = 1 + len += 4; + break; + case 0x0033: // mystery + break; + case 0x001d: // Multi-Read + case 0x001E: // CD Read + case 0x0027: // CD-RW CAV Write + case 0x002A: // DVD+RW + case 0x002B: // DVD+R + case 0x002D: // CD Track at Once + case 0x002E: // CD Mastering + case 0x002F: // DVD-R/-RW Write + case 0x003B: // DVD+R Double Layer + default: // un-supported; + break; + } + } + + putu32(data, len-2); + tio_set(tio, min_t(u16, len, getu16(scb+7)), 0); + res = 0; + + return res; +} +#endif + +#if 0 +static int build_seek10_response(struct iscsi_cmnd *cmnd) +{ + struct iscsi_scsi_cmd_hdr *req = cmnd_hdr(cmnd); + struct tio *tio = cmnd->tio; + u8 *data; + u8 *scb = req->scb; + int res = -1; + + dprintk(D_RMMC, "addr{%02x %02x %02x %02x}, " + "ctrl %02x\n", + scb[2], scb[3], scb[4], scb[5], + scb[9]); + + tio = cmnd->tio = tio_alloc(1); + data = page_address(tio->pvec[0]); + assert(data); + clear_page(data); + + tio->offset = 2048*be32_to_cpu((u32*)(scb+2)); + tio->size = 0; + res = 0; + + return res; +} +#endif + +#if 0 +static int build_subchannel_response(struct iscsi_cmnd *cmnd) +{ + struct iscsi_scsi_cmd_hdr *req = cmnd_hdr(cmnd); + u8 *scb = req->scb; + int res = -1, subq, param; + + subq = (scb[2]&0x40)>>6; + param = scb[3]; + dprintk(D_RMMC, "time %u, subq %u, param %u, tr-num %u, " + "al-len %02x %02x, ctrl %02x\n", + (scb[1]&0x02)>>1, subq, param, scb[6], + scb[7], scb[8], scb[9]); + return -1; + +#if 0 + struct tio *tio = cmnd->tio; + u8 *data, len = 4; + + tio = cmnd->tio = tio_alloc(1); + data = page_address(tio->pvec[0]); + assert(data); + clear_page(data); + + data[1] = 0x15; // audio status + switch (param) { + char *p; + case 1: // current pos. + data[3] = 12; + p = data+8; + p[0] = 1; // magic number + p[1] = ; + p[2] = p[3] = 1; // track and index + break; + default: + dprintk(D_RMMC, "not implememted\n"); + break; + } + + tio->size = len; + res = 0; + + tio->size = min_t(u8, tio->size, scb[8]); + + return res; +#endif +} +#endif + +static int +rmmc_error(struct iscsi_cmnd *cmnd) +{return -1;} + +static int +rmmc_execute_cmnd(struct iscsi_cmnd *cmnd) +{ + struct iscsi_scsi_cmd_hdr *req = cmnd_hdr(cmnd); + + req->opcode &= ISCSI_OPCODE_MASK; + +#if 1 + switch (req->scb[0]) { + case TEST_UNIT_READY: + case READ_10: + case GPCMD_REPORT_KEY: + case GPCMD_SEND_KEY: + case READ_CAPACITY: + case INQUIRY: + case GPCMD_MODE_SENSE_10: + case GPCMD_READ_TOC_PMA_ATIP: + break; + case GPCMD_READ_DVD_STRUCTURE: + case GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL: + break; + case GPCMD_READ_SUBCHANNEL: + case GPCMD_READ_DISC_INFO: + case GPCMD_GET_EVENT_STATUS_NOTIFICATION: + case GPCMD_READ_TRACK_RZONE_INFO: + break; + default: + dprintk(D_RMMC, "scsi cmd %s(%02x)\n", + opstr(req->scb[0]), req->scb[0]); + } +#endif + + switch (req->scb[0]) { + case INQUIRY: + send_data_rsp(cmnd, rmmc_inquiry); + break; + case READ_CAPACITY: + send_data_rsp(cmnd, rmmc_capacity); + break; + case GPCMD_MODE_SENSE_10: + send_data_rsp(cmnd, rmmc_mode_sense10); + break; + case GPCMD_READ_TOC_PMA_ATIP: + send_data_rsp(cmnd, rmmc_tpa); + break; + case GPCMD_READ_DVD_STRUCTURE: + send_data_rsp(cmnd, rmmc_dvdst); + break; + case GPCMD_REPORT_KEY: + send_data_rsp(cmnd, rmmc_report_key); + break; + case GPCMD_SEND_KEY: + send_scsi_rsp(cmnd, rmmc_send_key); + break; + case READ_6: + case READ_10: + case READ_16: + send_data_rsp(cmnd, rmmc_read); + break; + case TEST_UNIT_READY: + send_scsi_rsp(cmnd, rmmc_tur); + break; + + // common to disk ope. + case REPORT_LUNS: + case MODE_SENSE: + case REQUEST_SENSE: + case SERVICE_ACTION_IN: + case START_STOP: + case SYNCHRONIZE_CACHE: + case VERIFY: + case VERIFY_16: + case RESERVE: + case RELEASE: + case RESERVE_10: + case RELEASE_10: + return disk_ops.execute_cmnd(cmnd); + + // tmp + case GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL: + send_scsi_rsp(cmnd, rmmc_medium_removal); + break; + case GPCMD_GET_EVENT_STATUS_NOTIFICATION: + send_data_rsp(cmnd, rmmc_event); + break; + case GPCMD_READ_DISC_INFO: + send_data_rsp(cmnd, rmmc_discinfo); + break; + + default: + do { + struct iscsi_conn *conn; + struct socket *sock; + struct sock *sk; + struct inet_sock *inet; + conn = cmnd->conn; + if (!conn) break; + sock = conn->sock; + if (!sock) break; + sk = sock->sk; + if (!sk) break; + inet = inet_sk(sk); + if (!inet) break; + dprintk(D_RMMC, "bad op %02x from ip %08x\n", + req->scb[0], inet->daddr); + } while (0); + + // make them errors + case GPCMD_READ_TRACK_RZONE_INFO: + //send_data_rsp(cmnd, rmmc_track_info); + //break; + case GPCMD_GET_CONFIGURATION: + //send_data_rsp(cmnd, rmmc_get_config); + //break; + case GPCMD_SEEK: + //send_data_rsp(cmnd, build_seek10_response); + //break; + case GPCMD_READ_CD_MSF: + case GPCMD_READ_CD: + + // always an error, silently + case WRITE_6: + case WRITE_10: + case WRITE_16: + case WRITE_VERIFY: + case GPCMD_READ_SUBCHANNEL: + send_scsi_rsp(cmnd, rmmc_error); + break; + } + + return 0; +} + +/* ---------------------------------------------------------------------- */ + +int +rmmc_conn_alloc(struct iscsi_conn conn[]) +{ + struct rmmc_conn *mconn; + u8 a[2]; + + mconn = kmalloc(sizeof(*mconn), GFP_KERNEL); + if (!mconn) return -ENOMEM; + //dprintk(D_RMMC, "rmmc_conn %p\n", mconn); + memset(mconn, 0, sizeof(*mconn)); + get_random_bytes(a, 2); + mconn->css.agid = a[0]&3; + mconn->css.variant = a[1]%10; + //dprintk(D_RMMC, "agid %d, variant %d\n", mconn->css.agid, mconn->css.variant); + + conn->private = mconn; + return 0; +} + +int +rmmc_conn_free(struct iscsi_conn conn[]) +{ + if (!conn->private) return 0; + kfree(conn->private); + //dprintk(D_RMMC, "freed rmmc_conn %p\n", conn->private); + conn->private = NULL; + return 0; +} + + +struct target_type rmmc_ops = +{ + .id = 1, // 'Type' in the config file. + .execute_cmnd = rmmc_execute_cmnd, + .conn_alloc = rmmc_conn_alloc, + .conn_free = rmmc_conn_free, +}; Index: iet-0.4.8/kernel/tio.c diff -u iet-0.4.8/kernel/tio.c:1.1.1.1 iet-0.4.8/kernel/tio.c:1.4 --- iet-0.4.8/kernel/tio.c:1.1.1.1 Tue May 24 12:46:19 2005 +++ iet-0.4.8/kernel/tio.c Tue May 31 13:59:35 2005 @@ -8,7 +8,8 @@ #include "iscsi_dbg.h" #include "iotype.h" -static int tio_add_pages(struct tio *tio, int count) +//static +int tio_add_pages(struct tio *tio, int count) { int i; struct page *page; @@ -38,13 +39,14 @@ static kmem_cache_t *tio_cache; -struct tio *tio_alloc(int count) +struct tio *_tio_alloc(int count, int add_pages_now) { struct tio *tio; tio = kmem_cache_alloc(tio_cache, GFP_KERNEL | __GFP_NOFAIL); tio->pg_cnt = 0; + tio->need_pages = 0; tio->idx = 0; tio->offset = 0; tio->size = 0; @@ -52,8 +54,10 @@ atomic_set(&tio->count, 1); - if (count) + if (count && add_pages_now) tio_add_pages(tio, count); + else + tio->need_pages = count; return tio; } Index: iet-0.4.8/kernel/wthread.c diff -u iet-0.4.8/kernel/wthread.c:1.1.1.1 iet-0.4.8/kernel/wthread.c:1.4 --- iet-0.4.8/kernel/wthread.c:1.1.1.1 Tue May 24 12:46:19 2005 +++ iet-0.4.8/kernel/wthread.c Tue May 31 13:59:35 2005 @@ -50,7 +50,7 @@ static int cmnd_execute(struct iscsi_cmnd *cmnd) { - int type = cmnd->conn->session->target->target_type; + int type = cmnd->conn->session->target->trgt_param.target_type; assert(target_type_array[type]->execute_cmnd); return target_type_array[type]->execute_cmnd(cmnd); Index: iet-0.4.8/usr/Makefile diff -u iet-0.4.8/usr/Makefile:1.1.1.1 iet-0.4.8/usr/Makefile:1.3 --- iet-0.4.8/usr/Makefile:1.1.1.1 Tue May 24 12:46:31 2005 +++ iet-0.4.8/usr/Makefile Tue May 24 13:34:22 2005 @@ -1,5 +1,5 @@ CFLAGS += -O2 -fno-inline -Wall -Wstrict-prototypes -g -I../include -PROGRAMS = ietd ietadm +PROGRAMS = ietd ietadm rmmcgen all: $(PROGRAMS) @@ -12,3 +12,7 @@ clean: rm -f *.o $(PROGRAMS) + +rmmcgen.o: CPPFLAGS += -I../css-auth -DNDEBUG +rmmcgen.o: CPPFLAGS += -UNDEBUG -O0 +rmmcgen: $(addprefix ../css-auth/, $(addsuffix .c, css-auth csstable)) Index: iet-0.4.8/usr/iscsid.c diff -u iet-0.4.8/usr/iscsid.c:1.1.1.1 iet-0.4.8/usr/iscsid.c:1.5 --- iet-0.4.8/usr/iscsid.c:1.1.1.1 Tue May 24 12:46:31 2005 +++ iet-0.4.8/usr/iscsid.c Tue May 31 20:14:47 2005 @@ -261,6 +261,10 @@ struct sockaddr_in name; socklen_t len; + /* always require user account */ + if (account_empty(conn->tid, AUTH_DIR_INCOMING)) + return -EACCES; + len = sizeof(name); getsockname(conn->fd, (struct sockaddr *)&name, &len); @@ -592,6 +596,7 @@ static void cmnd_exec_logout(struct connection *conn) { +// how do i remove the session? struct iscsi_logout_req_hdr *req = (struct iscsi_logout_req_hdr *)&conn->req.bhs; struct iscsi_logout_rsp_hdr *rsp = (struct iscsi_logout_rsp_hdr *)&conn->rsp.bhs; Index: iet-0.4.8/usr/log.c diff -u iet-0.4.8/usr/log.c:1.1.1.1 iet-0.4.8/usr/log.c:1.3 --- iet-0.4.8/usr/log.c:1.1.1.1 Tue May 24 12:46:31 2005 +++ iet-0.4.8/usr/log.c Mon May 23 21:46:21 2005 @@ -18,7 +18,7 @@ void log_init(void) { if (log_daemon) - openlog("iscsid", 0, LOG_DAEMON); + openlog("ietd" /*"iscsid"*/, 0, LOG_DAEMON); } static void dolog(int prio, const char *fmt, va_list ap) @@ -64,19 +64,22 @@ static void __dump_line(int level, unsigned char *buf, int *cp) { - char line[16*3+5], *lp = line; + char line[16*3+2*4+1], *lp = line; int i, cnt; cnt = *cp; if (!cnt) return; + *lp = 0; for (i = 0; i < 16; i++) { +#if 0 if (i < cnt) lp += sprintf(lp, " %02x", buf[i]); else lp += sprintf(lp, " "); if ((i % 4) == 3) lp += sprintf(lp, " |"); +#endif if (i >= cnt || !isprint(buf[i])) buf[i] = ' '; } @@ -98,7 +101,7 @@ void log_pdu(int level, struct PDU *pdu) { - unsigned char char_buf[16]; + unsigned char char_buf[16+1]; int char_cnt = 0; unsigned char *buf; int i; @@ -107,6 +110,7 @@ if (log_level <= level) return; + char_buf[sizeof(char_buf)-1] = 0; buf = (void *)&pdu->bhs; log_debug(level, "BHS: (%p)", buf); for (i = 0; i < BHS_SIZE; i++) Index: iet-0.4.8/usr/param.c diff -u iet-0.4.8/usr/param.c:1.1.1.1 iet-0.4.8/usr/param.c:1.3 --- iet-0.4.8/usr/param.c:1.1.1.1 Tue May 24 12:46:31 2005 +++ iet-0.4.8/usr/param.c Thu May 26 01:57:09 2005 @@ -23,7 +23,7 @@ struct iscsi_key target_keys[] = { {"Wthreads", SET_KEY_VALUES(WTHREADS), &minimum_ops}, - {"Type", 0, 16, 0, &minimum_ops}, + {"Type", 0, 0, 16, &minimum_ops}, {"QueuedCommands", SET_KEY_VALUES(QUEUED_CMNDS), &minimum_ops}, {NULL,}, }; Index: iet-0.4.8/usr/rmmcgen.c diff -u /dev/null iet-0.4.8/usr/rmmcgen.c:1.3 --- /dev/null Fri Jun 3 11:12:25 2005 +++ iet-0.4.8/usr/rmmcgen.c Fri Jun 3 11:09:55 2005 @@ -0,0 +1,1381 @@ + +/* + * based upon tstdvd.c of css-auth tools, which is,,, + * Copyright (C) 1999 Andrew T. Veliath + * See http://www.rpi.edu/~veliaa/linux-dvd for more info. + * + * and arranged by Junjiro Okajima for ietd read-only mmc interface. + * Copyright (C) 2005 Junjiro Okajima + */ + +static char rmmcgen_c[] __attribute__((unused, nocommon)) += "@(#) $Id: rmmcgen.c,v 1.3 2005/06/03 02:09:55 jro Exp $"; // " " __DATE__ " " __TIME__ + +//#define _LARGEFILE_SOURCE +//#define _LARGEFILE64_SOURCE +#define _FILE_OFFSET_BITS 64 + +/* -------------------- tstdvd.c -------------------- */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(__OpenBSD__) +# include +#elif defined(__linux__) +# include +#else +# error "Need the DVD ioctls" +#endif +#include "css-auth.h" + +byte Challenge[10]; +struct block Key1; +struct block Key2; +struct block KeyCheck; +byte DiscKey[10]; +int varient = -1; +int agid = -1; + +#if 0 +void print_challenge(const byte *chal) +{ + int i; + + for (i = 0; i < 10; ++i) + printf(" %02X", chal[9-i] & 0xff); +} + +void print_key(const byte *key) +{ + int i; + + for (i = 0; i < 5; ++i) + printf(" %02X", key[4-i] & 0xff); +} + + +void print_five(const byte *key) +{ + int i; + + for (i = 0; i < 5; ++i) + printf(" %02X", key[i] & 0xff); +} +#endif + +int authenticate_drive(const byte *key) +{ + int i; + + for (i=0; i<5; i++) + Key1.b[i] = key[4-i]; + + for (i = 0; i < 32; ++i) + { + CryptKey1(i, Challenge, &KeyCheck); + if (memcmp(KeyCheck.b, Key1.b, 5)==0) + { + varient = i; + //printf("Drive Authentic - using varient %d\n", i); + return 1; + } + } + + if (varient == -1) + printf("Drive would not Authenticate\n"); + + return 0; +} + +#if 0 +int GetDiscKey(int fd, int agid, char *key) +{ + dvd_struct s; + int index, fdd; + + s.type = DVD_STRUCT_DISCKEY; + s.disckey.agid = agid; + memset(s.disckey.value, 0, 2048); + if (ioctl(fd, DVD_READ_STRUCT, &s)<0) + { + printf("Could not read Disc Key\n"); + return 0; + } + + //printf ("Received Disc Key:\t"); + for (index=0; indextype) { + /* Host data receive (host changes state) */ + case DVD_LU_SEND_AGID: + //printf("AGID %d\n", ai->lsa.agid); + ai->type = DVD_HOST_SEND_CHALLENGE; + break; + + case DVD_LU_SEND_KEY1: + //printf("LU sent key1: "); print_key(ai->lsk.key); printf("\n"); + if (!authenticate_drive(ai->lsk.key)) { + ai->type = DVD_AUTH_FAILURE; + return -EINVAL; + } + ai->type = DVD_LU_SEND_CHALLENGE; + break; + + case DVD_LU_SEND_CHALLENGE: + for (i = 0; i < 10; ++i) + Challenge[i] = ai->hsc.chal[9-i]; + //printf("LU sent challenge: "); print_challenge(Challenge); printf("\n"); + CryptKey2(varient, Challenge, &Key2); + ai->type = DVD_HOST_SEND_KEY2; + break; + + /* Host data send */ + case DVD_HOST_SEND_CHALLENGE: + for (i = 0; i < 10; ++i) + ai->hsc.chal[9-i] = Challenge[i]; + //printf("Host sending challenge: "); print_challenge(Challenge); printf("\n"); + /* Returning data, let LU change state */ + break; + + case DVD_HOST_SEND_KEY2: + for (i = 0; i < 5; ++i) + ai->hsk.key[4-i] = Key2.b[i]; + //printf("Host sending key 2: "); print_key(Key2.b); printf("\n"); + /* Returning data, let LU change state */ + break; + + default: + printf("Got invalid state %d\n", ai->type); + return -EINVAL; + } + + return 0; +} + +int authenticate(int fd, int title, int lba) +{ + dvd_authinfo ai; + dvd_struct dvds; + int i, rv, tries; + + memset(&ai, 0, sizeof (ai)); + memset(&dvds, 0, sizeof (dvds)); + + GetASF(fd); + + /* Init sequence, request AGID */ + for (tries = 1, rv = -1; rv == -1 && tries < 4; ++tries) { + //printf("Request AGID [%d]...\t", tries); + ai.type = DVD_LU_SEND_AGID; + ai.lsa.agid = 0; + rv = ioctl(fd, DVD_AUTH, &ai); + if (rv == -1) { + //perror("N/A, invalidating"); + ai.type = DVD_INVALIDATE_AGID; + ai.lsa.agid = 0; + ioctl(fd, DVD_AUTH, &ai); + } + } + if (tries == 4) { + printf("Cannot get AGID\n"); + return -1; + } + + for (i = 0; i < 10; ++i) + Challenge[i] = i; + + /* Send AGID to host */ + if (hostauth(&ai) < 0) { + printf("Send AGID to host failed\n"); + return -1; + } + /* Get challenge from host */ + if (hostauth(&ai) < 0) { + printf("Get challenge from host failed\n"); + return -1; + } + if (agid == -1) + agid = ai.lsa.agid; + else if (agid != ai.lsa.agid) { + printf("AGID have been changed. Try again\n"); + return -1; + } + /* Send challenge to LU */ + if (ioctl(fd, DVD_AUTH, &ai) < 0) { + printf("Send challenge to LU failed\n"); + return -1; + } + /* Get key1 from LU */ + { + struct timespec req; + req.tv_sec = 1; + req.tv_nsec = 0; + nanosleep(&req, NULL); + } + if (ioctl(fd, DVD_AUTH, &ai) < 0) { + printf("Get key1 from LU failed\n"); + return -1; + } + /* Send key1 to host */ + if (hostauth(&ai) < 0) { + printf("Send key1 to host failed\n"); + return -1; + } + /* Get challenge from LU */ + if (ioctl(fd, DVD_AUTH, &ai) < 0) { + printf("Get challenge from LU failed\n"); + return -1; + } + /* Send challenge to host */ + if (hostauth(&ai) < 0) { + printf("Send challenge to host failed\n"); + return -1; + } + /* Get key2 from host */ + if (hostauth(&ai) < 0) { + printf("Get key2 from host failed\n"); + return -1; + } + /* Send key2 to LU */ + if (ioctl(fd, DVD_AUTH, &ai) < 0) { + printf("Send key2 to LU failed (expected)\n"); + return -1; + } + + if (ai.type == DVD_AUTH_ESTABLISHED) + ;//printf("DVD is authenticated\n"); + else if (ai.type == DVD_AUTH_FAILURE) + printf("DVD authentication failed\n"); + + memcpy(Challenge, Key1.b, 5); + memcpy(Challenge+5, Key2.b, 5); + CryptBusKey(varient, Challenge, &KeyCheck); +#if 0 + printf("Received Session Key:\t"); + for (i= 0; i< 5; i++) + { + printf("%02X ", KeyCheck.b[i]); + } + printf("\n"); + + GetASF(fd); + + if (title) + GetTitleKey(fd, agid, lba, KeyCheck.b); + else + GetDiscKey(fd, agid, KeyCheck.b); + + GetASF(fd); +#endif + + return 0; +} + +#ifndef FIBMAP +#define FIBMAP 1 +#endif + +#if 0 +int path_to_lba(char *p) +{ + int fd, lba = 0; + + if ((fd = open(p, O_RDONLY)) == -1) { + perror("DVD vob file:"); + return 0; + } + if (ioctl(fd, FIBMAP, &lba) != 0) { + perror("ioctl FIBMAP failed:"); + close(fd); + return 0; + } + + close(fd); + + return lba; +} +#endif + +/* ---------------------------------------------------------------------- */ +#include +#include +#include +#include +#include +#include + +#include "types.h" +#include "param.h" +#include "config.h" +#include "rmmc_aux.h" + +enum {Device, Img, Aux, LastFile}; +struct f { + char *fname; + int fd; + FILE *fp; +}; + +struct opts { + char genimg:1; + char genaux:1; + char dumpaux:1; + char quiet:1; + char *name; + char *device; + char *mntpnt; +}; + +// should be all uppercase. +#define VTSDir "VIDEO_TS" + +/* ---------------------------------------- */ + +int +openthem(struct f f[], struct opts opts[]) +{ + struct f *p; + int found, n; + struct dirent *de; + DIR *dir; + + if (opts->mntpnt && *opts->mntpnt) { + /* is it udf? */ + dir = opendir(opts->mntpnt); + if (!dir) return -1; + found = 0; + while (!found && (de = readdir(dir)) != NULL) + found = (strcasecmp(de->d_name, VTSDir) == 0); + errno = ENXIO; + if (!found) return -1; + } + + if (opts->device && *opts->device) { + p = f+Device; + p->fname = opts->device; + p->fd = open(p->fname, O_RDONLY/*|O_NONBLOCK*/); + if (p->fd < 0) return -1; + } + + p = f+Aux; + if (opts->dumpaux) { + p->fname = opts->name; + p->fd = open(p->fname, O_RDONLY); + if (p->fd < 0) return -1; + } else if (opts->genaux) { + n = strlen(opts->name); +#define AuxExt ".aux" + p->fname = malloc(n+sizeof(AuxExt)); + if (!p->fname) return -1; + strcpy(p->fname, opts->name); + strcpy(p->fname+n, AuxExt); +#undef AuxExt + p->fd = open(p->fname, O_RDWR|O_CREAT|O_EXCL, 0644); + if (p->fd < 0) return -1; + p->fp = fdopen(p->fd, "r+"); + if (!p->fp) return -1; + } + + return 0; +} + +/* ---------------------------------------- */ + +inline struct cdrom_generic_command* +getcgc(u16 len) +{ + static struct cdrom_generic_command cgc; + static u8 a[4096]; + + assert(len <= sizeof(a)); + memset(&cgc, 0, sizeof(cgc)); + cgc.buffer = a; + cgc.buflen = len; + cgc.data_direction = CGC_DATA_READ; + cgc.timeout = 5*HZ; + return &cgc; +} + +inline u8* +do_ioctl(int fd, struct cdrom_generic_command cgc[]) +{ + int ret; + + ret = ioctl(fd, CDROM_SEND_PACKET, cgc); + if (ret) return NULL; + return cgc->buffer; +} + +inline u8* +do_discinfo(int fd, u16 len) +{ + struct cdrom_generic_command *cgc; + + cgc = getcgc(len); + cgc->cmd[0] = GPCMD_READ_DISC_INFO; + putu16(cgc->cmd+7, len); + return do_ioctl(fd, cgc); +} + +inline u8* +do_dvdst(int fd, u8 num, u8 kind, u16 len, u8 agid) +{ + struct cdrom_generic_command *cgc; + + cgc = getcgc(len); + cgc->cmd[0] = GPCMD_READ_DVD_STRUCTURE; + cgc->cmd[6] = num; + cgc->cmd[7] = kind; + putu16(cgc->cmd+8, len); + cgc->cmd[10] = agid<<6; + return do_ioctl(fd, cgc); +} + +inline u8* +do_tpa(int fd, u8 msf, u8 fmt, u8 num, u16 len) +{ + struct cdrom_generic_command *cgc; + + cgc = getcgc(len); + cgc->cmd[0] = GPCMD_READ_TOC_PMA_ATIP; + cgc->cmd[1] = (msf&1)<<1; + cgc->cmd[2] = fmt&0xf; + cgc->cmd[6] = num; + putu16(cgc->cmd+7, len); + return do_ioctl(fd, cgc); +} + +inline u8* +do_rkey(int fd, u32 lba, u16 len, u8 agid, u8 kind) +{ + struct cdrom_generic_command *cgc; + + cgc = getcgc(len); + cgc->cmd[0] = GPCMD_REPORT_KEY; + putu32(cgc->cmd+2, lba); + cgc->cmd[7] = 0; + putu16(cgc->cmd+8, len); + cgc->cmd[10] = agid<<6; + cgc->cmd[10] |= kind; + return do_ioctl(fd, cgc); +} + +/* ---------------------------------------- */ + +int +putdiscinfo(FILE fp[], int fd) +{ + int ret; + u32 tlen; + struct rmmc_aux_discinfo discinfo; + u16 len; + u8 *p; + +#if 1 + assert(sizeof(discinfo) == 0); +#else + u32 start; + start = ftell(fp); + if (start == -1) goto err; + ret = fseek(fp, sizeof(discinfo), SEEK_CUR); + if (ret == -1) goto err; + + memset(&discinfo, 0, sizeof(discinfo)); +#endif + + tlen = 0; +#define ReqLen 1024 + p = do_discinfo(fd, ReqLen+1); + if (!p) goto err; + len = getu16(p)+2; + assert(len <= ReqLen); +#undef ReqLen + ret = fwrite(p, len, 1, fp); + if (ret != 1) goto err; + tlen += len; + +#if 0 + ret = fseek(fp, start, SEEK_SET); + if (ret == -1) goto err; + ret = fwrite(&discifno, sizeof(discinfo), 1, fp); + if (ret != 1) goto err; + ret = fseek(fp, tlen, SEEK_CUR); + if (ret == -1) goto err; +#endif + return sizeof(discinfo)+tlen; + err: + return -1; +} + +int +putlayer(FILE fp[], int fd, int num, u8 nlayer[]) +{ + int ret; + u32 start, tlen; + struct rmmc_aux_layer layer; + u16 len; + u8 *p; + + start = ftell(fp); + if (start == -1) goto err; + ret = fseek(fp, sizeof(layer), SEEK_CUR); + if (ret == -1) goto err; + + memset(&layer, 0, sizeof(layer)); + tlen = 0; +#define ReqLen 4+2048 + p = do_dvdst(fd, num, DVD_STRUCT_PHYSICAL, ReqLen+1, agid); + if (!p) goto err; + if (nlayer) { + *nlayer = (p[4+2]>>5) & 3; + (*nlayer)++; + } + len = getu16(p)+2; + assert(len <= ReqLen); + ret = fwrite(p, len, 1, fp); + if (ret != 1) goto err; + set_offlen(layer.offlen+DslPhys, tlen, len); + tlen += len; + + p = do_dvdst(fd, num, DVD_STRUCT_COPYRIGHT, ReqLen+1, agid); + if (!p) goto err; + len = getu16(p)+2; + assert(len <= ReqLen); + ret = fwrite(p, len, 1, fp); + if (ret != 1) goto err; + set_offlen(layer.offlen+DslCprt, tlen, len); + tlen += len; + + p = do_dvdst(fd, num, DVD_STRUCT_MANUFACT, ReqLen+1, agid); + if (!p) goto err; + len = getu16(p)+2; + assert(len <= ReqLen); +#undef ReqLen + ret = fwrite(p, len, 1, fp); + if (ret != 1) goto err; + set_offlen(layer.offlen+DslManuf, tlen, len); + tlen += len; + + ret = fseek(fp, start, SEEK_SET); + if (ret == -1) goto err; + ret = fwrite(&layer, sizeof(layer), 1, fp); + if (ret != 1) goto err; + ret = fseek(fp, tlen, SEEK_CUR); + if (ret == -1) goto err; + + return sizeof(layer)+tlen; + err: + return -1; +} + +int +putdvdst(FILE fp[], int fd) +{ + int i, ret; + u32 start, tlen; + struct rmmc_aux_dvdst dvdst; + u8 *p; + u16 len; + + start = ftell(fp); + if (start == -1) goto err; + ret = fseek(fp, sizeof(dvdst), SEEK_CUR); + if (ret == -1) goto err; + + memset(&dvdst, 0, sizeof(dvdst)); + tlen = 0; + dvdst.nlayer = DVD_LAYERS; + for (i = 0; i < dvdst.nlayer; i++) { + ret = putlayer(fp, fd, i, &dvdst.nlayer); + if (ret < 0) goto err; + set_offlen(dvdst.offlen+i, tlen, ret); + tlen += ret; + } + + ret = authenticate(fd, 0, 0); + if (ret) goto err; + p = do_dvdst(fd, 0, DVD_STRUCT_DISCKEY, sizeof(dvdst.dkey)+1, agid); + if (!p) goto err; + len = getu16(p)+2; + assert(len <= sizeof(dvdst.dkey)); + memcpy(dvdst.dkey, p, 4); + p += 4; + for (i = 0; i < sizeof(dvdst.dkey)-4; i++) + dvdst.dkey[4+i] = *p++ ^ KeyCheck.b[4 - (i%5)]; + + ret = fseek(fp, start, SEEK_SET); + if (ret == -1) goto err; + ret = fwrite(&dvdst, sizeof(dvdst), 1, fp); + if (ret != 1) goto err; + ret = fseek(fp, tlen, SEEK_CUR); + if (ret == -1) goto err; + + return sizeof(dvdst)+tlen; + err: + return -1; +} + +int +puttpa(FILE fp[], int fd) +{ + int ret, i; + u32 tlen; + struct rmmc_aux_dvdst tpa; + u16 len; + u8 *p; + +#if 1 + assert(sizeof(tpa) == 0); +#else + u32 start; + start = ftell(fp); + if (start == -1) goto err; + ret = fseek(fp, sizeof(tpa), SEEK_CUR); + if (ret == -1) goto err; + + memset(&tpa, 0, sizeof(tpa)); +#endif + + tlen = 0; + for (i = 0; i < 2; i++) { +#define ReqLen 4+2048 + p = do_tpa(fd, i, 0, 0, ReqLen+1); + if (!p) goto err; + len = getu16(p)+2; + assert(len <= ReqLen); +#undef ReqLen + ret = fwrite(p, len, 1, fp); + if (ret != 1) goto err; + tlen += len; + } +#if 0 + ret = fseek(fp, start, SEEK_SET); + if (ret == -1) goto err; + ret = fwrite(&tpa, sizeof(tpa), 1, fp); + if (ret != 1) goto err; + ret = fseek(fp, tlen, SEEK_CUR); + if (ret == -1) goto err; +#endif + return sizeof(tpa)+tlen; + err: + return -1; + +} + +int +puttitle(FILE fp[], int fd, char name[], int need_to_sort[]) +{ + static int lastlba; + int ret, lba, i, ffd; + struct rmmc_aux_tk tk; + struct stat st; + u8 *p; + u16 len; + + ffd = open(name, O_RDONLY); + if (ffd < 0) goto err; + ret = fstat(ffd, &st); + if (ret) goto err; + // ignore empty files. + if (!st.st_size) return 0; + lba = 0; + ret = ioctl(ffd, FIBMAP, &lba); + //printf("path %s, lba %d\n", name, lba); + if (ret) goto err; + //if (!lba) goto err; // lba can be zero. ?? + if (lastlba == lba) goto err; + if (lastlba > lba) (*need_to_sort)++; + lastlba = lba; + close(ffd); + + ret = authenticate(fd, 0, 0); + if (ret) goto err; +#define ReqLen 4+8 + p = do_rkey(fd, lba, ReqLen+1, agid, 4/* 4 is for title key*/); + if (!p) goto err; + len = getu16(p)+2; + assert(len <= ReqLen); +#undef ReqLen + + memset(&tk, 0, sizeof(tk)); + tk.lba[0] = cpu_to_be32(lba); + // st_blksize and st_blocks are broken. + tk.lba[1] = cpu_to_be32(lba+st.st_size/2048-1); + //printf("%s: lba %u, %u\n", name, be32_to_cpu(tk.lba[0]), be32_to_cpu(tk.lba[1])); + tk.cpbits = p[4+0]; + for (i = 0; i < sizeof(tk.tk); i++) + tk.tk[i] = p[4+1+i] ^ KeyCheck.b[4 - (i%5)]; + ret = fwrite(&tk, sizeof(tk), 1, fp); + if (ret != 1) goto err; + + return sizeof(tk); + err: + return -1; +} + +int +compar(const void *aa, const void *bb) +{ + const struct rmmc_aux_tk *a = aa, *b = bb; + //printf("%d, %d\n", be32_to_cpu(a->lba[0]), be32_to_cpu(b->lba[0])); + return be32_to_cpu(a->lba[0]) - be32_to_cpu(b->lba[0]); +} + +int +sorttk(FILE fp[], int start, int ntitle) +{ + u8 *p; + int len, ret, pagesize, m, fd; + + ret = fflush(fp); + if (ret) goto err; + fd = fileno(fp); + if (fd < 0) goto err; + pagesize = sysconf(_SC_PAGESIZE); + if (!pagesize) goto err; + m = start%pagesize; + len = ntitle*sizeof(struct rmmc_aux_tk); + p = mmap(NULL, len+m, PROT_READ|PROT_WRITE, MAP_SHARED, fd, start-m); + if (p == MAP_FAILED) goto err; + qsort(p+m, ntitle, sizeof(struct rmmc_aux_tk), compar); + /* tiny test */ + { + int i; + struct rmmc_aux_tk *tk; + tk = (void*)p+m; + for (i = 0; i < ntitle-1; i++) { + assert(be32_to_cpu(tk[i].lba[0]) < be32_to_cpu(tk[i].lba[1])); + assert(be32_to_cpu(tk[i].lba[1]) < be32_to_cpu(tk[i+1].lba[0])); + } + assert(be32_to_cpu(tk[i].lba[0]) < be32_to_cpu(tk[i].lba[1])); + } + ret = munmap(p, len+m); + if (ret) goto err; + return 0; + err: + return -1; +} + +int +putrkey(FILE fp[], int fd) +{ + int ret, ntitle, n, need_to_sort; + u32 start, tlen; + struct rmmc_aux_rkey rkey; + DIR *dir; + struct dirent *de; + + memset(&rkey, 0, sizeof(rkey)); + start = ftell(fp); + if (start == -1) goto err; + ret = fseek(fp, sizeof(rkey), SEEK_CUR); + if (ret == -1) goto err; + + need_to_sort = 0; + tlen = 0; + ntitle = 0; + dir = opendir("."); + if (!dir) goto err; + while ((de = readdir(dir)) != NULL) { + n = strlen(de->d_name); + if (n < 7) continue; + if (strcasecmp(de->d_name+n-4, ".VOB")) continue; + + // ret can be zero. + ret = puttitle(fp, fd, de->d_name, &need_to_sort); + if (ret < 0) goto err; + if (ret) ntitle++; + tlen += ret; + } + + if (need_to_sort) { + ret = sorttk(fp, start+sizeof(rkey), ntitle); + if (ret) goto err; + } + + rkey.ntitle = cpu_to_be32(ntitle); + ret = fseek(fp, start, SEEK_SET); + if (ret == -1) goto err; + ret = fwrite(&rkey, sizeof(rkey), 1, fp); + if (ret != 1) goto err; + ret = fseek(fp, tlen, SEEK_CUR); + if (ret == -1) goto err; + + return sizeof(rkey)+tlen; + err: + return -1; +} + +/* ----------------------------------------------------------------------*/ + +int +writeaux(FILE fp[], int fd, struct opts opts[]) +{ + struct rmmc_aux_file aux; + int ret, tlen; + + if (!opts->quiet) { + printf("Generating aux ..."); + fflush(stdout); + } + + // reserve the place for aux as a header + ret = fseek(fp, sizeof(aux), SEEK_SET); + if (ret == -1) goto err; + + memset(&aux, 0, sizeof(aux)); + tlen = 0; + + ret = putdiscinfo(fp, fd); + if (ret == -1) goto err; + set_offlen(aux.offlen+DISC_INFO, tlen, ret); + tlen += ret; + + ret = putdvdst(fp, fd); + if (ret == -1) goto err; + set_offlen(aux.offlen+DVD_STRUCTURE, tlen, ret); + tlen += ret; + +#if 0 + ret = puttpa(fp, fd); + if (ret == -1) goto err; + set_offlen(aux.offlen+TOC_PMA_ATIP, tlen, ret); + tlen += ret; +#endif + + ret = putrkey(fp, fd); + if (ret == -1) goto err; + set_offlen(aux.offlen+REPORT_KEY, tlen, ret); + tlen += ret; + + // write aux as the header + rewind(fp); + strcpy(aux.magic, RmmcAuxMagicStr); + //aux.version = cpu_to_be32(0); + aux.size = cpu_to_be32(tlen); + //aux.sum = 0; + //aux.salt; + ret = fwrite(&aux, sizeof(aux), 1, fp); + if (ret != 1) goto err; + ret = fflush(fp); + if (ret) goto err; + fd = fileno(fp); + ret = fsync(fd); + if (ret) goto err; + + /* set readonly */ + ret = fchmod(fd, 0444); + if (ret) goto err; + + if (!opts->quiet) printf(" done\n"); + return 0; + err: + return -1; +} + +/* ---------------------------------------- */ + +int +dumpaux(int fd) +{ + struct stat st; + int ret, i; + struct rmmc_aux_file *aux; + u32 len; + struct rmmc_aux_discinfo *disci; + struct rmmc_aux_dvdst *dvdst; + struct rmmc_aux_tpa *tpa; + struct rmmc_aux_rkey *rkey; + + ret = fstat(fd, &st); + if (ret) goto err; + if (st.st_size < sizeof(*aux)) goto badfile; + aux = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); + if (aux == MAP_FAILED) goto err; + + if (memcmp(aux->magic, RmmcAuxMagicStr, sizeof(RmmcAuxMagicStr)-1)) goto badfile; + printf("version: %d\n" + "data size: %d\n", + be32_to_cpu(aux->version), be32_to_cpu(aux->size)); + + disci = offlen_discinfo(aux, &len); + if (!disci) goto badfile; + if (!len) + printf("no discinfo\n"); + else { +#if 0 + struct { + u16 len; + u8 res1:3; + u8 erasable:1; + u8 laststat:2; + u8 discstat:1; + u8 nftrack; + u8 nsess_lsb; + u8 ftrack_lastsess_lsb; + u8 ltrack_lastsess_lsb; + u8 did_v:1; + u8 dbc_v:1; + u8 uru:1; + u8 dac_v:1; + u8 res2:1; + u8 dbit:1; + u8 bg:2; + u8 disctype; + u8 nsess_msb; + u8 ftrack_lastsess_msb; + u8 ltrack_lastsess_msb; + u32 discid; + u32 lin_last; + u32 lout; + u8 barcode[8]; + u8 apcode; + u8 nopc; + u8 opc[0]; + } *di; +#endif + u8 *p; + p = (void*)disci; + printf("discinfo{%02x %02x %02x %02x ...}\n", + p[0], p[1], p[2], p[3]); + } + + dvdst = offlen_dvdst(aux, &len); + if (!dvdst) goto badfile; + if (!len) + printf("no dvdst\n"); + else { + struct rmmc_aux_phys { + u16 len; + u8 res1[2]; + /* layer descriptor */ + u8 booktype:4; + u8 partver:4; + u8 discsize:4; + u8 maxrate:4; + u8 res2:1; + u8 nlayer:2; + u8 track_path:1; + u8 layertype:4; + u8 lineardensity:4; + u8 trackdensity:4; + u32 startsect; + u32 endsect; + u32 endlayer0; + u8 bca:1; + u8 res3:7; + u8 data[0]; + } *phys; + + struct rmmc_aux_cprt { + u16 len; + u8 res1[2]; + + /* copyright info */ + u8 cpst; + u8 rmt; + u8 res2[2]; + } *cprt; + + printf("dvd structure\nnlayer: %d\n", dvdst->nlayer); + for (i = 0; i < dvdst->nlayer; i++) { + struct rmmc_aux_layer *layer; + layer = offlen_layer(dvdst, i, &len); + if (!layer) goto badfile; + printf("layer %d: physical(%d)+copyright(%d)+manufacture(%d)\n", + i, + be32_to_cpu(layer->offlen[DslPhys].length), + be32_to_cpu(layer->offlen[DslCprt].length), + be32_to_cpu(layer->offlen[DslManuf].length)); + + phys = (void*)offlen_phys(layer, &len); + if (!phys) goto badfile; + printf("phys{\n" + "\tlen: %u\n" + "\tbooktype: %01xh\n" + "\tpartver: %01xh\n" + "\tdiscsize: %01xh\n" + "\tmaxrate: %01xh\n" + "\tnlayer: %01xh\n" + "\ttrack_path: %01xh\n" + "\tlayertype: %01xh\n" + "\tlineardensity: %01xh\n" + "\ttrackdensity: %01xh\n" + "\tstartsect: %u\n" + "\tendsect: %u\n" + "\tendlayer0: %u\n" + "\tbca: %01xh\n" + "}\n", + be16_to_cpu(phys->len), + phys->booktype, + phys->partver, + phys->discsize, + phys->maxrate, + phys->nlayer, + phys->track_path, + phys->layertype, + phys->lineardensity, + phys->trackdensity, + be32_to_cpu(phys->startsect), + be32_to_cpu(phys->endsect), + be32_to_cpu(phys->endlayer0), + phys->bca); + + cprt = (void*)offlen_cprt(layer, &len); + if (!cprt) goto badfile; + printf("copyright{\n" + "\tlen: %04xh\n" + "\tcpst: %02xh\n" + "\trmt: %02xh\n" + "}\n", + be16_to_cpu(cprt->len), + cprt->cpst, + cprt->rmt); + } + } + + tpa = offlen_tpa(aux, &len); + if (!tpa) goto badfile; + if (!len) + printf("no toc_pma_atip\n"); + else { + } + + rkey = offlen_rkey(aux, &len); + if (!rkey) goto badfile; + if (!rkey) + printf("no rkey\n"); + else { + int n; + struct rmmc_aux_tk *tk; + n = be32_to_cpu(rkey->ntitle); + printf("report key{\n" + "\tntitle: %d\n", + n); + tk = rkey->data; + for (i = 0; i < n; i++) { + printf("\tlba %d - %d, cpbits %02xh\n", + be32_to_cpu(tk->lba[0]), be32_to_cpu(tk->lba[1]), tk->cpbits); + tk++; + } + printf("}\n"); + } + + return 0; + + badfile: + printf("bad file"); + errno = EBADF; + err: + return -1; +} + +/* ---------------------------------------- */ +#include +#include + +int doprint; +void +progress(int sig, siginfo_t si[], void *data) +{doprint++;} + + +/* ---------------------------------------- */ + +int +parse(int argc, char *argv[], struct opts opts[]) +{ + int c; + + opts->device = opts->mntpnt = NULL; + while ((c = getopt(argc, argv, "n:iad:vhq")) != -1) { + switch (c) { + case 'n': + //if (!optarg || !*optarg) goto usage; + opts->name = optarg; + break; + case 'a': opts->genimg = 0; opts->genaux = 1; break; + case 'd': + // hidden option + opts->genimg = opts->genaux = 0; + opts->dumpaux = 1; + opts->name = optarg; + break; + case 'q': opts->quiet = 1; break; + case 'v': goto version; + case 'h': + default: + goto usage; + } + } + + // hidden option + if (opts->dumpaux) return 0; + + if (optind+2 != argc) goto usage; + opts->device = argv[optind]; + opts->mntpnt = argv[optind+1]; + return 0; + + usage: + fprintf(stderr, "usage: %s [-n basename] [-iavhq] device mntpnt\n" + "\t-a: generate aux only.\n" + "\t-q: dont show progress info.\n" + "\t-v: show version and exit.\n" + "\t-h: show this help and exit.\n" + "note1: device must be mounted at the mntpnt.\n" + "note2: aux filename is always '.aux'.\n" + , argv[0]); + /*FALLTHROUGH*/ + version: + printf("$Id: rmmcgen.c,v 1.3 2005/06/03 02:09:55 jro Exp $\n"); + return -1; + +} + +int +main(int argc, char *argv[]) +{ + char *me, *pre; + int ret; + struct f f[LastFile]; + char lower[sizeof(VTSDir)]; + int i; + struct statfs stf; + struct opts opts; + + pre = me = *argv; + memset(&opts, 0, sizeof(opts)); + opts.genimg = opts.genaux = 1; + opts.name = "./img"; + ret = parse(argc, argv, &opts); + if (ret) return EINVAL; + + /* open files */ + memset(f, 0, sizeof(f)); + pre = "openthem"; + ret = openthem(f, &opts); + if (ret) goto err; + + /* chdir to the dir where .VOB is */ + memset(&stf, 0, sizeof(stf)); + if (opts.mntpnt) { + pre = opts.mntpnt; + ret = chdir(opts.mntpnt); + if (ret) goto err; + pre = VTSDir; + ret = chdir(VTSDir); + if (ret) { + if (errno != ENOENT) goto err; + for (i = 0; i < sizeof(VTSDir); i++) + lower[i] = tolower(VTSDir[i]); + pre = lower; + ret = chdir(lower); + if (ret) goto err; + } + + ret = statfs(".", &stf); + if (ret) goto err; + } + + if (opts.dumpaux) { + pre = "dumpaux"; + ret = dumpaux(f[Aux].fd); + if (ret) goto err; + return 0; + } + + if (opts.genaux) { + pre = "writeaux"; + ret = writeaux(f[Aux].fp, f[Device].fd, &opts); + if (ret) goto err; + } + + + return 0; + err: + ret = errno; + perror(pre); + return ret; +}