#include <sys/param.h>
#include <sys/disklabel.h>
#include <luna88k/stand/boot/samachdep.h>
#include <luna88k/stand/boot/scsireg.h>
#include <luna88k/stand/boot/scsivar.h>
struct sd_softc {
uint sc_ctlr;
uint sc_tgt;
uint sc_part;
short sc_type;
short sc_punit;
u_short sc_bshift;
daddr32_t sc_blks;
int sc_blksize;
struct disklabel sc_label;
struct scsi_softc sc_sc;
};
struct sd_softc *sdinit(uint, uint);
static int sdident(struct sd_softc *);
static struct scsi_inquiry inqbuf;
static struct scsi_generic_cdb inq = {
6,
{ CMD_INQUIRY, 0, 0, 0, sizeof(inqbuf), 0 }
};
static u_long capbuf[2];
struct scsi_generic_cdb cap = {
10,
{ CMD_READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};
int
sdident(struct sd_softc *sc)
{
#ifdef DEBUG
char idstr[32];
#endif
uint ctlr, target, unit;
int i;
int tries = 10;
ctlr = sc->sc_ctlr;
target = sc->sc_tgt;
unit = sc->sc_punit;
if (scinit(&sc->sc_sc, ctlr) == 0)
return -1;
while ((i = scsi_test_unit_rdy(&sc->sc_sc, target, unit)) != 0) {
if (i < 0 || --tries < 0)
return (-1);
if (i == STS_CHECKCOND) {
u_char sensebuf[8];
struct scsi_xsense *sp = (struct scsi_xsense *)sensebuf;
scsi_request_sense(&sc->sc_sc, target, unit, sensebuf,
sizeof sensebuf);
if (sp->class == 7 && sp->key == 6)
DELAY(1000000);
}
DELAY(1000);
}
if (scsi_immed_command(&sc->sc_sc, target, unit, &inq,
(u_char *)&inqbuf, sizeof(inqbuf)) ||
scsi_immed_command(&sc->sc_sc, target, unit, &cap,
(u_char *)&capbuf, sizeof(capbuf)))
return (-1);
switch (inqbuf.type) {
case 0:
case 4:
case 5:
case 7:
break;
default:
return (-1);
}
sc->sc_blks = capbuf[0];
sc->sc_blksize = capbuf[1];
#ifdef DEBUG
memcpy(idstr, &inqbuf.vendor_id, 28);
for (i = 27; i > 23; --i)
if (idstr[i] != ' ')
break;
idstr[i+1] = 0;
for (i = 23; i > 7; --i)
if (idstr[i] != ' ')
break;
idstr[i+1] = 0;
for (i = 7; i >= 0; --i)
if (idstr[i] != ' ')
break;
idstr[i+1] = 0;
printf("sd(%d,%d): %s %s rev %s", ctlr, target, idstr, &idstr[8],
&idstr[24]);
printf(", %d bytes/sect x %d sectors\n", sc->sc_blksize, sc->sc_blks);
#endif
if (sc->sc_blksize != DEV_BSIZE) {
if (sc->sc_blksize < DEV_BSIZE) {
printf("sd(%d,%d): need %d byte blocks - drive ignored\n",
ctlr, target, DEV_BSIZE);
return (-1);
}
for (i = sc->sc_blksize; i > DEV_BSIZE; i >>= 1)
++sc->sc_bshift;
sc->sc_blks <<= sc->sc_bshift;
}
return(inqbuf.type);
}
struct sd_softc *
sdinit(uint unit, uint part)
{
struct sd_softc *sc;
struct disklabel *lp;
char *msg;
sc = alloc(sizeof *sc);
if (sc == NULL)
return NULL;
memset(sc, 0, sizeof *sc);
sc->sc_ctlr = unit / 10;
sc->sc_tgt = unit % 10;
sc->sc_part = part;
#ifdef DEBUG
printf("sdinit: ctlr = %d tgt = %d part = %d\n",
sc->sc_ctlr, sc->sc_tgt, sc->sc_part);
#endif
sc->sc_punit = 0;
sc->sc_type = sdident(sc);
if (sc->sc_type < 0)
return(NULL);
lp = &sc->sc_label;
if (lp->d_secpercyl == 0) {
lp->d_secsize = DEV_BSIZE;
lp->d_nsectors = 32;
lp->d_ntracks = 20;
lp->d_secpercyl = 32*20;
lp->d_npartitions = 1;
lp->d_partitions[0].p_offset = 0;
lp->d_partitions[0].p_size = LABELSECTOR + 1;
}
msg = readdisklabel(&sc->sc_sc, sc->sc_tgt, lp);
if (msg != NULL)
printf("sd(%d,%d): %s\n", sc->sc_ctlr, sc->sc_tgt, msg);
return sc;
}
int
sdopen(struct open_file *f, ...)
{
va_list ap;
struct sd_softc *sc;
int unit, part;
va_start(ap, f);
unit = va_arg(ap, int);
part = va_arg(ap, int);
va_end(ap);
if (part < 0 || part >= MAXPARTITIONS)
return(-1);
sc = sdinit(unit, part);
if (sc == NULL)
return -1;
f->f_devdata = (void *)sc;
return 0;
}
int
sdclose(struct open_file *f)
{
struct sd_softc *sc = f->f_devdata;
free(sc, sizeof *sc);
f->f_devdata = NULL;
return 0;
}
static struct scsi_generic_cdb cdb_read = {
10,
{ CMD_READ_EXT, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};
static struct scsi_generic_cdb cdb_write = {
10,
{ CMD_WRITE_EXT, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};
int
sdstrategy(void *devdata, int func, daddr_t dblk, size_t size, void *v_buf,
size_t *rsize)
{
struct sd_softc *sc = devdata;
struct disklabel *lp;
uint8_t *buf = v_buf;
int target = sc->sc_tgt;
struct scsi_generic_cdb *cdb;
daddr32_t blk;
u_int nblk = size >> sc->sc_bshift;
int stat;
#ifdef DEBUG
int i;
#endif
lp = &sc->sc_label;
blk = dblk + (lp->d_partitions[sc->sc_part].p_offset >> sc->sc_bshift);
if (func == F_READ)
cdb = &cdb_read;
else
cdb = &cdb_write;
cdb->cdb[2] = (blk & 0xff000000) >> 24;
cdb->cdb[3] = (blk & 0x00ff0000) >> 16;
cdb->cdb[4] = (blk & 0x0000ff00) >> 8;
cdb->cdb[5] = (blk & 0x000000ff);
cdb->cdb[7] = ((nblk >> _DEV_BSHIFT) & 0xff00) >> 8;
cdb->cdb[8] = ((nblk >> _DEV_BSHIFT) & 0x00ff);
#ifdef DEBUG
printf("sdstrategy(%d,%d): blk = %lu (0x%lx), nblk = %u (0x%x)\n",
sc->sc_ctlr, sc->sc_tgt, (u_long)blk, (long)blk, nblk, nblk);
for (i = 0; i < 10; i++)
printf("cdb[%d] = 0x%x\n", i, cdb->cdb[i]);
#endif
stat = scsi_immed_command(&sc->sc_sc, target, sc->sc_punit, cdb, buf,
size);
if (rsize)
*rsize = size;
return 0;
}