2104 lines · 47.2 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ /* * multi-media commands * * as of mmc-6, mode page 0x2a (capabilities & mechanical status) is legacy * and read-only, last defined in mmc-3.  mode page 5 (write parameters) * applies only to cd-r(w) and dvd-r(w); *-rom, dvd+* and bd-* are right out. */#include <u.h>#include <libc.h>#include <disk.h>#include "../scuzz/scsireq.h"#include "dat.h"#include "fns.h" enum{	Desperate	= 0,	/* non-zero grubs around in inquiry string */ 	Pagesz		= 255, 	Pagerrrecov	= 1,	/* error recovery */	Pagwrparams	= 5,	/* (cd|dvd)-r(w) device write parameters */	Pagcache	= 8,	Pagcapmechsts	= 0x2a, 	Invistrack	= 0xff,	/* the invisible & incomplete track */	Maxresptracks	= 120,	/* (1024-slop) / 8 */ 	/* Pagerrrecov error control bits (buf[2]) */	Erawre	= 1<<7,		/* recover from write errors */	Erarre	= 1<<6,		/* recover from read errors */	Ertb	= 1<<5,		/* transfer bad block to host */	Errc	= 1<<4,		/* read continuous; no error recovery */	Erper	= 1<<2,		/* post error: report recovered errors */	Erdte	= 1<<1,		/* disable transfer on error */	Erdcr	= 1<<0,		/* disable correction */ 	Kilo	= 1000LL,	GB	= Kilo * Kilo * Kilo,}; typedef struct Intfeat Intfeat;typedef struct Mmcaux Mmcaux; static Dev mmcdev; struct Mmcaux {	/* drive characteristics */	uchar	page05[Pagesz];		/* write parameters */	int	page05ok;	int	pagecmdsz; 	/* disc characteristics */	long	mmcnwa;			/* next writable address (block #) */	int	nropen;	int	nwopen;	vlong	ntotby;	long	ntotbk;}; struct Intfeat {	int	numb;	char	*name;}; enum {	Featrandwrite	= 0x20,	Featdfctmgmt	= 0x24,	Featwriteonce	= 0x25,	Featedfctrpt	= 0x29,	Featdvdrw	= 0x2a,}; Intfeat intfeats[] = {	Featrandwrite,	"random writable",	/* for write-and-verify *///	0x21,		"incr. streaming writable",	Featdfctmgmt,	"hw defect mgmt.",	Featwriteonce,	"write once",		/* for write-and-verify */	Featedfctrpt,	"enhanced defect reporting",	Featdvdrw,	"dvd+rw",		/* for dvd write-and-verify */	0x38,		"pseudo-overwrite",//	0x40,		"bd read",//	0x41,		"bd write",}; /* these will be printed as user ids, so no spaces please */static char *dvdtype[] = {	"dvd-rom",	"dvd-ram",	"dvd-r",	"dvd-rw",	"hd-dvd-rom",	"hd-dvd-ram",	"hd-dvd-r",	"type-7-unknown",	"type-8-unknown",	"dvd+rw",	"dvd+r",	"type-11-unknown",	"type-12-unknown",	"dvd+rw-dl",	"dvd+r-dl",	"type-15-unknown",}; static int format(Drive *drive);static int getinvistrack(Drive *drive); static ulongbige(void *p){	uchar *a; 	a = p;	return (a[0]<<24)|(a[1]<<16)|(a[2]<<8)|(a[3]<<0);} static ushortbiges(void *p){	uchar *a; 	a = p;	return (a[0]<<8) | a[1];} ulonggetnwa(Drive *drive){	Mmcaux *aux; 	aux = drive->aux;	return aux->mmcnwa;} static voidhexdump(void *v, int n){	int i;	uchar *p; 	p = v;	for(i=0; i<n; i++){		print("%.2ux ", p[i]);		if((i%8) == 7)			print("\n");	}	if(i%8)		print("\n");} static voidinitcdb(uchar *cdb, int len, int cmd){	memset(cdb, 0, len);	cdb[0] = cmd;} /* * SCSI CDBs (cmd arrays) are 6, 10, 12, 16 or 32 bytes long. * The mode sense/select commands implicitly refer to * a mode parameter list, which consists of an 8-byte * mode parameter header, followed by zero or more block * descriptors and zero or more mode pages (MMC-2 §5.5.2). * We'll ignore mode sub-pages. * Integers are stored big-endian. * * The format of the mode parameter (10) header is: *	ushort	mode_data_length;		// of following bytes *	uchar	medium_type; *	uchar	device_specific; *	uchar	reserved[2]; *	ushort	block_descriptor_length;	// zero * * The format of the mode parameter (6) header is: *	uchar	mode_data_length;		// of following bytes *	uchar	medium_type; *	uchar	device_specific; *	uchar	block_descriptor_length;	// zero * * The format of the mode pages is: *	uchar	page_code_and_PS; *	uchar	page_len;			// of following bytes *	uchar	parameter[page_len]; * * see SPC-3 §4.3.4.6 for allocation length and §7.4 for mode parameter lists. */ enum {	Mode10parmhdrlen= 8,	Mode6parmhdrlen	= 4,	Modepaghdrlen	= 2,}; static intmmcgetpage10(Drive *drive, int page, void *v){	uchar cmd[10], resp[512];	int n, r; 	initcdb(cmd, sizeof cmd, ScmdMsense10);	cmd[2] = page;	cmd[8] = 255;			/* allocation length: buffer size */	n = scsi(drive, cmd, sizeof(cmd), resp, sizeof(resp), Sread);	if(n < Mode10parmhdrlen)		return -1; 	r = (resp[6]<<8) | resp[7];	/* block descriptor length */	n -= Mode10parmhdrlen + r; 	if(n < 0)		return -1;	if(n > Pagesz)		n = Pagesz; 	memmove(v, &resp[Mode10parmhdrlen + r], n);	return n;} static intmmcgetpage6(Drive *drive, int page, void *v){	uchar cmd[6], resp[512];	int n; 	initcdb(cmd, sizeof cmd, ScmdMsense6);	cmd[2] = page;	cmd[4] = 255;			/* allocation length */ 	n = scsi(drive, cmd, sizeof(cmd), resp, sizeof(resp), Sread);	if(n < Mode6parmhdrlen)		return -1; 	n -= Mode6parmhdrlen + resp[3];	if(n < 0)		return -1;	if(n > Pagesz)		n = Pagesz; 	memmove(v, &resp[Mode6parmhdrlen + resp[3]], n);	return n;} static intmmcsetpage10(Drive *drive, int page, void *v){	uchar cmd[10], *p, *pagedata;	int len, n; 	/* allocate parameter list, copy in mode page, fill in header */	pagedata = v;	assert(pagedata[0] == page);	len = Mode10parmhdrlen + Modepaghdrlen + pagedata[1];	p = emalloc(len);	memmove(p + Mode10parmhdrlen, pagedata, pagedata[1]);	/* parameter list header */	p[0] = 0;	p[1] = len - 2; 	/* set up CDB */	initcdb(cmd, sizeof cmd, ScmdMselect10);	cmd[1] = 0x10;			/* format not vendor-specific */	cmd[8] = len; //	print("set: sending cmd\n");//	hexdump(cmd, 10);//	print("parameter list header\n");//	hexdump(p, Mode10parmhdrlen);//	print("page\n");//	hexdump(p + Mode10parmhdrlen, len - Mode10parmhdrlen); 	n = scsi(drive, cmd, sizeof(cmd), p, len, Swrite); //	print("set: got cmd\n");//	hexdump(cmd, 10); 	free(p);	if(n < len)		return -1;	return 0;} static intmmcsetpage6(Drive *drive, int page, void *v){	uchar cmd[6], *p, *pagedata;	int len, n; 	if (vflag)		print("mmcsetpage6 called!\n");	pagedata = v;	assert(pagedata[0] == page);	len = Mode6parmhdrlen + Modepaghdrlen + pagedata[1];	p = emalloc(len);	memmove(p + Mode6parmhdrlen, pagedata, pagedata[1]); 	initcdb(cmd, sizeof cmd, ScmdMselect6);	cmd[1] = 0x10;			/* format not vendor-specific */	cmd[4] = len; 	n = scsi(drive, cmd, sizeof(cmd), p, len, Swrite);	free(p);	if(n < len)		return -1;	return 0;} static intmmcgetpage(Drive *drive, int page, void *v){	Mmcaux *aux; 	aux = drive->aux;	switch(aux->pagecmdsz) {	case 10:		return mmcgetpage10(drive, page, v);	case 6:		return mmcgetpage6(drive, page, v);	default:		assert(0);	}	return -1;} static intmmcsetpage(Drive *drive, int page, void *v){	Mmcaux *aux; 	aux = drive->aux;	switch(aux->pagecmdsz) {	case 10:		return mmcsetpage10(drive, page, v);	case 6:		return mmcsetpage6(drive, page, v);	default:		assert(0);	}	return -1;} intmmcstatus(Drive *drive){	uchar cmd[12]; 	initcdb(cmd, sizeof cmd, ScmdCDstatus);		/* mechanism status */	return scsi(drive, cmd, sizeof(cmd), nil, 0, Sread);} voidmmcgetspeed(Drive *drive){	int n, maxread, curread, maxwrite, curwrite;	uchar buf[Pagesz]; 	memset(buf, 0, 22);	n = mmcgetpage(drive, Pagcapmechsts, buf);	/* legacy page */	if (n < 22) {		if (vflag)			fprint(2, "no Pagcapmechsts mode page!\n");		return;	}	maxread =   (buf[8]<<8)|buf[9];	curread =  (buf[14]<<8)|buf[15];	maxwrite = (buf[18]<<8)|buf[19];	curwrite = (buf[20]<<8)|buf[21]; 	if(maxread && maxread < 170 || curread && curread < 170)		return;			/* bogus data */ 	drive->readspeed = curread;	drive->writespeed = curwrite;	drive->maxreadspeed = maxread;	drive->maxwritespeed = maxwrite;} static intgetdevtype(Drive *drive){	int n;	uchar cmd[6], resp[Pagesz]; 	initcdb(cmd, sizeof cmd, ScmdInq);	cmd[3] = sizeof resp >> 8;	cmd[4] = sizeof resp;	n = scsi(drive, cmd, sizeof(cmd), resp, sizeof resp, Sread);	if (n < 8)		return -1;	return resp[0] & 037;} static intstart(Drive *drive, int code){	uchar cmd[6]; 	initcdb(cmd, sizeof cmd, ScmdStart);	cmd[4] = code;	return scsi(drive, cmd, sizeof(cmd), cmd, 0, Snone);} static intsetcaching(Drive *drive){	int n;	uchar buf[Pagesz]; 	/*	 * we can't actually control caching much.	 * see SBC-2 §6.3.3 but also MMC-6 §7.6.	 *	 * should set read ahead, MMC-6 §6.37; seems to control caching.	 */	n = mmcgetpage(drive, Pagcache, buf);	if (n < 3)		return -1;	/* n == 255; buf[1] == 10 (10 bytes after buf[1]) */	buf[0] &= 077;		/* clear reserved bits, MMC-6 §7.2.3 */	assert(buf[0] == Pagcache);	assert(buf[1] >= 10);	buf[2] = Ccwce;	if (mmcsetpage(drive, Pagcache, buf) < 0) {		if (vflag)			print("mmcprobe: cache control NOT set\n");		return -1;	}	return 0;} Drive*mmcprobe(Scsi *scsi){	Mmcaux *aux;	Drive *drive;	uchar buf[Pagesz];	int cap; 	if (vflag)		print("mmcprobe: inquiry: %s\n", scsi->inquire); 	drive = emalloc(sizeof(Drive));	drive->Scsi = *scsi;	drive->Dev = mmcdev;	drive->invistrack = -1;	getinvistrack(drive); 	aux = emalloc(sizeof(Mmcaux));	drive->aux = aux; 	scsiready(drive);	drive->type = getdevtype(drive);	if (drive->type != TypeCD) {		werrstr("not an mmc device");		free(aux);		free(drive);		return nil;	} 	/*	 * drive is an mmc device; learn what we can about it	 * (as opposed to the disc in it).	 */ 	start(drive, 1);	/* attempt to read CD capabilities page, but it's now legacy */	if(mmcgetpage10(drive, Pagcapmechsts, buf) >= 0)		aux->pagecmdsz = 10;	else if(mmcgetpage6(drive, Pagcapmechsts, buf) >= 0)		aux->pagecmdsz = 6;	else {		if (vflag)			fprint(2, "no Pagcapmechsts mode page!\n");		werrstr("can't read mode page %d!", Pagcapmechsts);		free(aux);		free(drive);		return nil;	} 	cap = 0;	if(buf[Capwrite] & (Capcdr|Capcdrw|Capdvdr|Capdvdram) ||	    buf[Capmisc] & Caprw)		cap |= Cwrite;	if(buf[Capmisc] & Capcdda)	/* CD-DA commands supported? */		cap |= Ccdda;		/* not used anywhere else */ //	print("read %d max %d\n", biges(buf+14), biges(buf+8));//	print("write %d max %d\n", biges(buf+20), biges(buf+18)); 	/* cache optional page 05 (write parameter page) */	if(/* (cap & Cwrite) && */

Lines 1–500 of 2104.