view arch/fba.c @ 96:a480d02a10c8

merge
author Jonathan Pevarnek <pevarnj@gmail.com>
date Sat, 14 May 2011 12:54:47 -0400
parents 40af39d064fa
children
line wrap: on
line source

#include "channel.h"

#include <die.h>

#define FBA_BLK_SIZE			512

#define DASD_FBA_WRITE			0x41
#define DASD_FBA_READ			0x42
#define DASD_FBA_LOCATE_RECORD		0x43
#define DASD_FBA_DEFINE_EXTENT		0x63

enum op_type {
	WRITE = 0,
	READ,
};

struct fba_DE_data {
	u8 perm:2,              /* Permissions on this extent */
	   __zero0:2,
	   da:1,
	   diag:1,              /* allow diagnose */
	   __zero1:2;
	u8 __zero3;
	u16 blksize;            /* Blocksize */
	u32 ext_loc;            /* Extent locator */
	u32 ext_beg;            /* logical number of block 0 in extent */
	u32 ext_end;            /* logocal number of last block in extent */
};

struct fba_LO_data {
	u8 zero:4,
	   cmd:4;
	u8 aux;
	u16 count;
	u32 blkno;
};

/* build a Define-Extent CCW */
static void fba_define_extent(struct ccw *ccw, struct fba_DE_data *data,
			      enum op_type rw, u16 blksize, u32 blkno, u32 len)
{
	ccw->cmd   = DASD_FBA_DEFINE_EXTENT;
	ccw->count = 0x10;
	ccw->addr  = (u32) (u64) data;

	__builtin_memset(data, 0, sizeof(struct fba_DE_data));
	switch(rw) {
		case WRITE:
			data->perm = 0x00;
			break;
		case READ:
			data->perm = 0x01;
			break;
		default:
			die();
			break;
	}
	data->blksize = blksize;
	data->ext_loc = blkno;
	data->ext_end = len - 1;
}

/* build a Locate-Record CCW */
static void fba_locate_record(struct ccw *ccw, struct fba_LO_data *data,
			      enum op_type rw, u32 blkno, u32 len)
{
	ccw->cmd   = DASD_FBA_LOCATE_RECORD;
	ccw->count = 0x08;
	ccw->addr  = (u32) (u64) data;

	__builtin_memset(data, 0, sizeof(struct fba_LO_data));
	switch(rw) {
		case WRITE:
			data->cmd = 0x05;
			break;
		case READ:
			data->cmd = 0x06;
			break;
		default:
			die();
			break;
	}
	data->blkno = blkno;
	data->count = len;
}

/* build a Read or Write CCW */
static void fba_readwrite(struct ccw *ccw, void *ptr, enum op_type rw, u32 len)
{
	if(len > 0xffff)
		die();

	switch(rw) {
		case 0:
			ccw->cmd = DASD_FBA_WRITE;
			break;
		case 1:
			ccw->cmd = DASD_FBA_READ;
			break;
		default:
			die();
			break;
	}

	ccw->count = len;
	ccw->addr  = (u32) (u64) ptr;
}

/**
 * fba_read_blk - read a block from an FBA device
 * @dev:	device to read from
 * @blkno:	block number to read
 * @ptr:	buffer to fill
 * @sync:	synchronous I/O
 */
static int __fba_readwrite_blk(u32 dev, u32 blkno, void *ptr, enum op_type dir)
{
	struct orb orb;
	struct ccw ccw[3];
	struct fba_DE_data defext;
	struct fba_LO_data locate;

	__builtin_memset(&orb, 0, sizeof(struct orb));
	orb.lpm = 0xff;
	orb.addr = (u32) (u64) ccw;
	orb.f = 1;

	__builtin_memset(ccw, 0, sizeof(ccw));

	/* Define-Extent */
	fba_define_extent(&ccw[0], &defext, dir, FBA_BLK_SIZE, blkno, 1);
	ccw[0].flags |= 0x40;

	/* Locate */
	fba_locate_record(&ccw[1], &locate, dir, 0, 1);
	ccw[1].flags |= 0x40;

	/* Read */
	fba_readwrite(&ccw[2], ptr, dir, FBA_BLK_SIZE);

	if (start_sch(dev, &orb))
		die();

	wait_for_io_int();

	return 0;
}

int fba_read_blk(u32 dev, u32 blkno, void *ptr)
{
	return __fba_readwrite_blk(dev, blkno, ptr, READ);
}

int fba_write_blk(u32 dev, u32 blkno, void *ptr)
{
	return __fba_readwrite_blk(dev, blkno, ptr, WRITE);
}