[comp.sys.next] scsi block size

nerd@percival.rain.com (Michael Galassi) (03/20/91)

Enclosed is a little program I wrote to check/change the block size of a
SCSI device.  The SCSI demo served as a guide-line for some parts of this.
There is no cute interface, no documentation, no makefile.  This for me
is a "use once and throw away" program.  My disk drive is now formated
at 1 K blocks.

Results of using 1 K blocks are that my wren runner is now about 20 Meg
larger than it was.  I can't tell if it is any faster in real use or not.

I have only tried this program with my wren runner and a wren V, it may
not work on any other drive.  You use it at your risk etc etc etc...

How to use the program.
**************************
* back up your hard disk *
**************************
**************************
* back up your hard disk *
**************************
**************************
* back up your hard disk *
**************************
**************************
* back up your hard disk *
**************************
compile the program, I used cc -o scsi_bsize scsi_bsize.c.
copy the binary onto an optical disk.
reboot the system from the same optical disk.
type "scsi_bsize -t 0", this should tell you your current block size.
type scsi_bsize -t 0 -b 1024", this should set the block size to 1 K.
if you want to do a drive other than target 0, try -t <whatever>.

You have the source, play with it and read it carefully before you
use this.  Remeber, its YOUR disk drive.

---- cut here and feed to /bin/sh or /bin/ksh ----

#!/bin/sh
# This is a shell archive (produced by shar 3.49)
# To extract the files from this archive, save it to a file, remove
# everything above the "!/bin/sh" line above, and type "sh file_name".
#
# made 02/26/1991 18:20 UTC by nerd@percy
# Source directory /usr/spool/uucppublic
#
# existing files will NOT be overwritten unless -c is specified
#
# This shar contains:
# length  mode       name
# ------ ---------- ------------------------------------------
#   4564 -rw-rw-rw- scsi_bsize.c
#
# ============= scsi_bsize.c ==============
if test -f 'scsi_bsize.c' -a X"$1" != X"-c"; then
	echo 'x - skipping scsi_bsize.c (File already exists)'
else
echo 'x - extracting scsi_bsize.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'scsi_bsize.c' &&
/*
** If called without parameters this program will read and display the
** block size of the scsi device.  If given a numeric parameter it will
** then set the block size of the device to that value (range 256 to 4096).
**
** by Michael Galassi (nerd@percival.rain.com) on 02/07/91 with some ideas
** taken from the scsi demo in /NextDeveloper/Expamples.
**
** This code worked for me, it is not guaranteed to work for anyone else.
** Feel free to use it as you wish at your own risk.
*/
X
#include <fcntl.h>
#include <stdio.h>
#include <sys/types.h>
#include <nextdev/scsireg.h>
X
static char *dev_name="/dev/sg0";	/* generic scsi interface */
static int lun = 0;
X
void show_block_size(int target);
void set_block_size(int target, int block_size);
int gs_mode_sense(int fd, int ccode, int clen, u_char *data);
int gs_mode_select(int fd, int clen, u_char *data);
int scsi_open(int target);
X
main(int argc, char *argv[])
{
X	extern int optind;
X	extern char *optarg;
X
X	char c;
X
X	int target = -1;
X	int blocksize = -1;
X
X	while ((c = getopt(argc, argv, "t:b:")) != EOF) {
X		switch (c) {
X		case 't':
X			target = atoi(optarg);
X			break;
X		case 'b':
X			blocksize = atoi(optarg);
X			break;
X		}
X	}
X	if (target == -1) {
X		fprintf(stderr,
X			"usage: %s -t<target> [-b<blocksize>]\n",
X			argv[0]);
X		exit(1);
X	}
/* if no blocksie given show current blocksize and exit */
X	if (blocksize == -1) {
X		show_block_size(target);
X		exit(0);
X	}
X
X	set_block_size(target, blocksize);
X	exit(0);
}
X
void show_block_size(int target)
{
X	u_char data[12];
X	int fd;
X	int block_size;
X
X	if ((fd = scsi_open(target)) < 0) {
X		fputs("error opening scsi device\n", stderr);
X		exit(1);
X	}
X	bzero(data, sizeof(data));
X	if(gs_mode_sense(fd, 0, 12, data)) {
X		fputs("error in mode sense\n", stderr);
X		close(fd);
X		exit(1);
X	}
X	block_size = (data[9] << 16) | (data[10] << 8) | data[11];
X	fprintf(stdout, "Block size: %d bytes\n", block_size);
X	close(fd);
}
X
int gs_mode_sense(int fd, int ccode, int clen, u_char *data)
{
X	struct scsi_req sr;
X	struct cdb_6 *cdbp = &sr.sr_cdb.cdb_c6;
X
X	bzero((char *)&sr, sizeof(sr));
X	cdbp->c6_opcode = C6OP_MODESENSE;
X	cdbp->c6_lun    = lun;
X	cdbp->c6_lba	= 0xc000 | ccode;	/* pcf is 11 (binary) */
X	cdbp->c6_len	= clen;
X	sr.sr_dma_dir	= SR_DMA_RD;
X	sr.sr_addr	= (caddr_t)data;
X	sr.sr_dma_max	= clen;
X	sr.sr_ioto	= 10;
X	return(do_ioc(fd, &sr));
}
X
void set_block_size(int target, int block_size)
{
X	u_char data[12];
X	int fd;
X
X	if ((fd = scsi_open(target)) < 0) {
X		fputs("error opening scsi device\n", stderr);
X		exit(1);
X	}
X	bzero(data, 12);
X	data[3] = 8;		/* 8 bytes of block descriptor */
X	data[9] = (block_size >> 16) & 0xff;
X	data[10] = (block_size >> 8) & 0xff;
X	data[11] = block_size & 0xff;
X	if(gs_mode_select(fd, 12, data)) {
X		close(fd);
X		fputs("gs_mode_select failed\n", stderr);
X		exit(1);
X	}
X	close(fd);
X	show_block_size(target);
}
X
int gs_mode_select(int fd, int clen, u_char *data)
{
X	struct scsi_req sr;
X	struct cdb_6 *cdbp = &sr.sr_cdb.cdb_c6;
X
X	bzero((char *)&sr, sizeof(sr));	/* clear struct out */
X
X	cdbp->c6_opcode = C6OP_MODESELECT;
X	cdbp->c6_lun    = lun;
X	cdbp->c6_lba	= 0x110000;	/* sets Save Mode Parameters bit */
X	cdbp->c6_len	= clen;
X	sr.sr_dma_dir	= SR_DMA_WR;
X	sr.sr_dma_max	= clen;
X	sr.sr_addr	= (caddr_t)data;
X	sr.sr_ioto	= 10;
X
X	return(do_ioc(fd, &sr));
}
X
int do_ioc(int fd, struct scsi_req *sr)
{
X	if (ioctl(fd, SGIOCREQ, sr) < 0) {
X		perror("ioctl(SGIOCREQ)");
X		return(-1);
X	}
X	if(sr->sr_io_status) {
X		fprintf(stderr,"sr_io_status = 0x%02X\n",sr->sr_io_status);
X		if(sr->sr_io_status == SR_IOST_CHKSV) {
X			fprintf(stderr,
X				"sense key = 0x%02X, sense code = 0x%02X\n",
X				sr->sr_esense.er_sensekey,
X				sr->sr_esense.er_addsensecode);
X		}
X		fprintf(stderr,"SCSI status = 0x%02X\n", sr->sr_scsi_status);
X		return(-1);
X	}
X	return(0);
}
X
int scsi_open(int target)
{
X	struct scsi_adr sa;
X	int fd;
X
X	if ((fd = open(dev_name, O_RDWR)) < 0) {
X		fprintf(stderr,"\nCould not open %s\n",dev_name);
X		return(-1);
X	}
X
X	sa.sa_target = target;
X	sa.sa_lun = lun;
X	if (ioctl(fd,SGIOCSTL,&sa) < 0) {
X		fprintf(stderr,"Error setting target %d lun %d\n",target,lun);
X		close(fd);
X		return(-1);
X	}
X
X	if(gs_request_sense(fd)) {		/* clear unit attention */
X		close(fd);
X		return(-1);
X	}
X	return(fd);
}
X
int gs_request_sense(int fd)
{
X	struct scsi_req sr;
X	struct cdb_6 *cdbp = &sr.sr_cdb.cdb_c6;
X	u_char sbuf[128];
X
X	bzero((char *)&sr, sizeof(sr));
X	cdbp->c6_opcode = C6OP_REQSENSE;
X	cdbp->c6_lun    = lun;
X	cdbp->c6_len	= 18;
X	sr.sr_dma_dir	= SR_DMA_RD;
X	sr.sr_addr	= (caddr_t)sbuf;
X	sr.sr_dma_max	= 128;
X	sr.sr_ioto	= 10;
X	return(do_ioc(fd, &sr));
}
SHAR_EOF
chmod 0666 scsi_bsize.c ||
echo 'restore of scsi_bsize.c failed'
Wc_c="`wc -c < 'scsi_bsize.c'`"
test 4564 -eq "$Wc_c" ||
	echo 'scsi_bsize.c: original size 4567, current size' "$Wc_c"
fi
exit 0
-- 
Michael Galassi				| nerd@percival.rain.com
MS-DOS:  The ultimate PC virus.		| ...!tektronix!percy!nerd