File: [local] / sys / scsi / safte.c (download)
Revision 1.1.1.1 (vendor branch), Tue Mar 4 16:16:06 2008 UTC (16 years, 6 months ago) by nbrk
Branch: OPENBSD_4_2_BASE, MAIN
CVS Tags: jornada-partial-support-wip, HEAD Changes since 1.1: +0 -0 lines
Import of OpenBSD 4.2 release kernel tree with initial code to support
Jornada 720/728, StrongARM 1110-based handheld PC.
At this point kernel roots on NFS and boots into vfs_mountroot() and traps.
What is supported:
- glass console, Jornada framebuffer (jfb) works in 16bpp direct color mode
(needs some palette tweaks for non black/white/blue colors, i think)
- saic, SA11x0 interrupt controller (needs cleanup)
- sacom, SA11x0 UART (supported only as boot console for now)
- SA11x0 GPIO controller fully supported (but can't handle multiple interrupt
handlers on one gpio pin)
- sassp, SSP port on SA11x0 that attaches spibus
- Jornada microcontroller (jmcu) to control kbd, battery, etc throught
the SPI bus (wskbd attaches on jmcu, but not tested)
- tod functions seem work
- initial code for SA-1111 (chip companion) : this is TODO
Next important steps, i think:
- gpio and intc on sa1111
- pcmcia support for sa11x0 (and sa1111 help logic)
- REAL root on nfs when we have PCMCIA support (we may use any of supported pccard NICs)
- root on wd0! (using already supported PCMCIA-ATA)
|
/* $OpenBSD: safte.c,v 1.37 2007/06/24 05:34:35 dlg Exp $ */
/*
* Copyright (c) 2005 David Gwynne <dlg@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "bio.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/scsiio.h>
#include <sys/malloc.h>
#include <sys/proc.h>
#include <sys/rwlock.h>
#include <sys/queue.h>
#include <sys/sensors.h>
#if NBIO > 0
#include <dev/biovar.h>
#endif
#include <scsi/scsi_all.h>
#include <scsi/scsiconf.h>
#include <scsi/safte.h>
#ifdef SAFTE_DEBUG
#define DPRINTF(x) do { if (safte_debug) printf x ; } while (0)
int safte_debug = 1;
#else
#define DPRINTF(x) /* x */
#endif
int safte_match(struct device *, void *, void *);
void safte_attach(struct device *, struct device *, void *);
int safte_detach(struct device *, int);
struct safte_sensor {
struct ksensor se_sensor;
enum {
SAFTE_T_FAN,
SAFTE_T_PWRSUP,
SAFTE_T_DOORLOCK,
SAFTE_T_ALARM,
SAFTE_T_TEMP
} se_type;
u_int8_t *se_field;
};
struct safte_softc {
struct device sc_dev;
struct scsi_link *sc_link;
struct rwlock sc_lock;
u_int sc_encbuflen;
u_char *sc_encbuf;
int sc_nsensors;
struct safte_sensor *sc_sensors;
struct ksensordev sc_sensordev;
struct sensor_task *sc_sensortask;
int sc_celsius;
int sc_ntemps;
struct safte_sensor *sc_temps;
u_int16_t *sc_temperrs;
#if NBIO > 0
int sc_nslots;
u_int8_t *sc_slots;
#endif
};
struct cfattach safte_ca = {
sizeof(struct safte_softc), safte_match, safte_attach, safte_detach
};
struct cfdriver safte_cd = {
NULL, "safte", DV_DULL
};
#define DEVNAME(s) ((s)->sc_dev.dv_xname)
int safte_read_config(struct safte_softc *);
void safte_read_encstat(void *);
#if NBIO > 0
int safte_ioctl(struct device *, u_long, caddr_t);
int safte_bio_blink(struct safte_softc *, struct bioc_blink *);
#endif
int64_t safte_temp2uK(u_int8_t, int);
int
safte_match(struct device *parent, void *match, void *aux)
{
struct scsi_attach_args *sa = aux;
struct scsi_inquiry_data *inq = sa->sa_inqbuf;
struct scsi_inquiry_data inqbuf;
struct scsi_inquiry cmd;
struct safte_inq *si = (struct safte_inq *)&inqbuf.extra;
int length, flags;
if (inq == NULL)
return (0);
/* match on dell enclosures */
if ((inq->device & SID_TYPE) == T_PROCESSOR &&
SCSISPC(inq->version) == 3)
return (2);
if ((inq->device & SID_TYPE) != T_PROCESSOR ||
SCSISPC(inq->version) != 2 ||
(inq->response_format & SID_ANSII) != 2)
return (0);
length = inq->additional_length + SAFTE_EXTRA_OFFSET;
if (length < SAFTE_INQ_LEN)
return (0);
if (length > sizeof(inqbuf))
length = sizeof(inqbuf);
memset(&cmd, 0, sizeof(cmd));
cmd.opcode = INQUIRY;
_lto2b(length, cmd.length);
memset(&inqbuf, 0, sizeof(inqbuf));
memset(&inqbuf.extra, ' ', sizeof(inqbuf.extra));
flags = SCSI_DATA_IN;
if (cold)
flags |= SCSI_AUTOCONF;
if (scsi_scsi_cmd(sa->sa_sc_link, (struct scsi_generic *)&cmd,
sizeof(cmd), (u_char *)&inqbuf, length, 2, 10000, NULL,
flags) != 0)
return (0);
if (memcmp(si->ident, SAFTE_IDENT, sizeof(si->ident)) == 0)
return (2);
return (0);
}
void
safte_attach(struct device *parent, struct device *self, void *aux)
{
struct safte_softc *sc = (struct safte_softc *)self;
struct scsi_attach_args *sa = aux;
int i = 0;
sc->sc_link = sa->sa_sc_link;
sa->sa_sc_link->device_softc = sc;
rw_init(&sc->sc_lock, DEVNAME(sc));
printf("\n");
sc->sc_encbuf = NULL;
sc->sc_nsensors = 0;
#if NBIO > 0
sc->sc_nslots = 0;
#endif
if (safte_read_config(sc) != 0) {
printf("%s: unable to read enclosure configuration\n",
DEVNAME(sc));
return;
}
if (sc->sc_nsensors > 0) {
sc->sc_sensortask = sensor_task_register(sc,
safte_read_encstat, 10);
if (sc->sc_sensortask == NULL) {
printf("%s: unable to register update task\n",
DEVNAME(sc));
sc->sc_nsensors = sc->sc_ntemps = 0;
free(sc->sc_sensors, M_DEVBUF);
} else {
for (i = 0; i < sc->sc_nsensors; i++)
sensor_attach(&sc->sc_sensordev,
&sc->sc_sensors[i].se_sensor);
sensordev_install(&sc->sc_sensordev);
}
}
#if NBIO > 0
if (sc->sc_nslots > 0 &&
bio_register(self, safte_ioctl) != 0) {
printf("%s: unable to register ioctl with bio\n", DEVNAME(sc));
sc->sc_nslots = 0;
} else
i++;
#endif
if (i) /* if we're doing something, then preinit encbuf and sensors */
safte_read_encstat(sc);
else {
free(sc->sc_encbuf, M_DEVBUF);
sc->sc_encbuf = NULL;
}
}
int
safte_detach(struct device *self, int flags)
{
struct safte_softc *sc = (struct safte_softc *)self;
int i;
rw_enter_write(&sc->sc_lock);
#if NBIO > 0
if (sc->sc_nslots > 0)
bio_unregister(self);
#endif
if (sc->sc_nsensors > 0) {
sensordev_deinstall(&sc->sc_sensordev);
sensor_task_unregister(sc->sc_sensortask);
for (i = 0; i < sc->sc_nsensors; i++)
sensor_detach(&sc->sc_sensordev,
&sc->sc_sensors[i].se_sensor);
free(sc->sc_sensors, M_DEVBUF);
}
if (sc->sc_encbuf != NULL)
free(sc->sc_encbuf, M_DEVBUF);
rw_exit_write(&sc->sc_lock);
return (0);
}
int
safte_read_config(struct safte_softc *sc)
{
struct safte_readbuf_cmd cmd;
struct safte_config config;
struct safte_sensor *s;
int flags, i, j;
memset(&cmd, 0, sizeof(cmd));
cmd.opcode = READ_BUFFER;
cmd.flags |= SAFTE_RD_MODE;
cmd.bufferid = SAFTE_RD_CONFIG;
cmd.length = htobe16(sizeof(config));
flags = SCSI_DATA_IN;
#ifndef SCSIDEBUG
flags |= SCSI_SILENT;
#endif
if (cold)
flags |= SCSI_AUTOCONF;
if (scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd,
sizeof(cmd), (u_char *)&config, sizeof(config), 2, 30000, NULL,
flags) != 0)
return (1);
DPRINTF(("%s: nfans: %d npwrsup: %d nslots: %d doorlock: %d ntemps: %d"
" alarm: %d celsius: %d ntherm: %d\n", DEVNAME(sc), config.nfans,
config.npwrsup, config.nslots, config.doorlock, config.ntemps,
config.alarm, SAFTE_CFG_CELSIUS(config.therm),
SAFTE_CFG_NTHERM(config.therm)));
sc->sc_encbuflen = config.nfans * sizeof(u_int8_t) + /* fan status */
config.npwrsup * sizeof(u_int8_t) + /* power supply status */
config.nslots * sizeof(u_int8_t) + /* device scsi id (lun) */
sizeof(u_int8_t) + /* door lock status */
sizeof(u_int8_t) + /* speaker status */
config.ntemps * sizeof(u_int8_t) + /* temp sensors */
sizeof(u_int16_t); /* temp out of range sensors */
sc->sc_encbuf = malloc(sc->sc_encbuflen, M_DEVBUF, M_NOWAIT);
if (sc->sc_encbuf == NULL)
return (1);
sc->sc_nsensors = config.nfans + config.npwrsup + config.ntemps +
(config.doorlock ? 1 : 0) + (config.alarm ? 1 : 0);
sc->sc_sensors = malloc(sc->sc_nsensors * sizeof(struct safte_sensor),
M_DEVBUF, M_NOWAIT);
if (sc->sc_sensors == NULL) {
free(sc->sc_encbuf, M_DEVBUF);
sc->sc_encbuf = NULL;
sc->sc_nsensors = 0;
return (1);
}
strlcpy(sc->sc_sensordev.xname, DEVNAME(sc),
sizeof(sc->sc_sensordev.xname));
memset(sc->sc_sensors, 0,
sc->sc_nsensors * sizeof(struct safte_sensor));
s = sc->sc_sensors;
for (i = 0; i < config.nfans; i++) {
s->se_type = SAFTE_T_FAN;
s->se_field = (u_int8_t *)(sc->sc_encbuf + i);
s->se_sensor.type = SENSOR_INDICATOR;
snprintf(s->se_sensor.desc, sizeof(s->se_sensor.desc),
"Fan%d", i);
s++;
}
j = config.nfans;
for (i = 0; i < config.npwrsup; i++) {
s->se_type = SAFTE_T_PWRSUP;
s->se_field = (u_int8_t *)(sc->sc_encbuf + j + i);
s->se_sensor.type = SENSOR_INDICATOR;
snprintf(s->se_sensor.desc, sizeof(s->se_sensor.desc),
"PSU%d", i);
s++;
}
j += config.npwrsup;
#if NBIO > 0
sc->sc_nslots = config.nslots;
sc->sc_slots = (u_int8_t *)(sc->sc_encbuf + j);
#endif
j += config.nslots;
if (config.doorlock) {
s->se_type = SAFTE_T_DOORLOCK;
s->se_field = (u_int8_t *)(sc->sc_encbuf + j);
s->se_sensor.type = SENSOR_INDICATOR;
strlcpy(s->se_sensor.desc, "doorlock",
sizeof(s->se_sensor.desc));
s++;
}
j++;
if (config.alarm) {
s->se_type = SAFTE_T_ALARM;
s->se_field = (u_int8_t *)(sc->sc_encbuf + j);
s->se_sensor.type = SENSOR_INDICATOR;
strlcpy(s->se_sensor.desc, "alarm", sizeof(s->se_sensor.desc));
s++;
}
j++;
/*
* stash the temp info so we can get out of range status. limit the
* number so the out of temp checks cant go into memory it doesnt own
*/
sc->sc_ntemps = (config.ntemps > 15) ? 15 : config.ntemps;
sc->sc_temps = s;
sc->sc_celsius = SAFTE_CFG_CELSIUS(config.therm);
for (i = 0; i < config.ntemps; i++) {
s->se_type = SAFTE_T_TEMP;
s->se_field = (u_int8_t *)(sc->sc_encbuf + j + i);
s->se_sensor.type = SENSOR_TEMP;
s++;
}
j += config.ntemps;
sc->sc_temperrs = (u_int16_t *)(sc->sc_encbuf + j);
return (0);
}
void
safte_read_encstat(void *arg)
{
struct safte_softc *sc = (struct safte_softc *)arg;
struct safte_readbuf_cmd cmd;
int flags, i;
struct safte_sensor *s;
u_int16_t oot;
rw_enter_write(&sc->sc_lock);
memset(&cmd, 0, sizeof(cmd));
cmd.opcode = READ_BUFFER;
cmd.flags |= SAFTE_RD_MODE;
cmd.bufferid = SAFTE_RD_ENCSTAT;
cmd.length = htobe16(sc->sc_encbuflen);
flags = SCSI_DATA_IN;
#ifndef SCSIDEBUG
flags |= SCSI_SILENT;
#endif
if (cold)
flags |= SCSI_AUTOCONF;
if (scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd,
sizeof(cmd), sc->sc_encbuf, sc->sc_encbuflen, 2, 30000, NULL,
flags) != 0) {
rw_exit_write(&sc->sc_lock);
return;
}
for (i = 0; i < sc->sc_nsensors; i++) {
s = &sc->sc_sensors[i];
s->se_sensor.flags &= ~SENSOR_FUNKNOWN;
DPRINTF(("%s: %d type: %d field: 0x%02x\n", DEVNAME(sc), i,
s->se_type, *s->se_field));
switch (s->se_type) {
case SAFTE_T_FAN:
switch (*s->se_field) {
case SAFTE_FAN_OP:
s->se_sensor.value = 1;
s->se_sensor.status = SENSOR_S_OK;
break;
case SAFTE_FAN_MF:
s->se_sensor.value = 0;
s->se_sensor.status = SENSOR_S_CRIT;
break;
case SAFTE_FAN_NOTINST:
case SAFTE_FAN_UNKNOWN:
default:
s->se_sensor.value = 0;
s->se_sensor.status = SENSOR_S_UNKNOWN;
s->se_sensor.flags |= SENSOR_FUNKNOWN;
break;
}
break;
case SAFTE_T_PWRSUP:
switch (*s->se_field) {
case SAFTE_PWR_OP_ON:
s->se_sensor.value = 1;
s->se_sensor.status = SENSOR_S_OK;
break;
case SAFTE_PWR_OP_OFF:
s->se_sensor.value = 0;
s->se_sensor.status = SENSOR_S_OK;
break;
case SAFTE_PWR_MF_ON:
s->se_sensor.value = 1;
s->se_sensor.status = SENSOR_S_CRIT;
break;
case SAFTE_PWR_MF_OFF:
s->se_sensor.value = 0;
s->se_sensor.status = SENSOR_S_CRIT;
break;
case SAFTE_PWR_NOTINST:
case SAFTE_PWR_PRESENT:
case SAFTE_PWR_UNKNOWN:
s->se_sensor.value = 0;
s->se_sensor.status = SENSOR_S_UNKNOWN;
s->se_sensor.flags |= SENSOR_FUNKNOWN;
break;
}
break;
case SAFTE_T_DOORLOCK:
switch (*s->se_field) {
case SAFTE_DOOR_LOCKED:
s->se_sensor.value = 1;
s->se_sensor.status = SENSOR_S_OK;
break;
case SAFTE_DOOR_UNLOCKED:
s->se_sensor.value = 0;
s->se_sensor.status = SENSOR_S_CRIT;
break;
case SAFTE_DOOR_UNKNOWN:
s->se_sensor.value = 0;
s->se_sensor.status = SENSOR_S_CRIT;
s->se_sensor.flags |= SENSOR_FUNKNOWN;
break;
}
break;
case SAFTE_T_ALARM:
switch (*s->se_field) {
case SAFTE_SPKR_OFF:
s->se_sensor.value = 0;
s->se_sensor.status = SENSOR_S_OK;
break;
case SAFTE_SPKR_ON:
s->se_sensor.value = 1;
s->se_sensor.status = SENSOR_S_CRIT;
break;
}
break;
case SAFTE_T_TEMP:
s->se_sensor.value = safte_temp2uK(*s->se_field,
sc->sc_celsius);
break;
}
}
oot = betoh16(*sc->sc_temperrs);
for (i = 0; i < sc->sc_ntemps; i++)
sc->sc_temps[i].se_sensor.status =
(oot & (1 << i)) ? SENSOR_S_CRIT : SENSOR_S_OK;
rw_exit_write(&sc->sc_lock);
}
#if NBIO > 0
int
safte_ioctl(struct device *dev, u_long cmd, caddr_t addr)
{
struct safte_softc *sc = (struct safte_softc *)dev;
int error = 0;
switch (cmd) {
case BIOCBLINK:
error = safte_bio_blink(sc, (struct bioc_blink *)addr);
break;
default:
error = EINVAL;
break;
}
return (error);
}
int
safte_bio_blink(struct safte_softc *sc, struct bioc_blink *blink)
{
struct safte_writebuf_cmd cmd;
struct safte_slotop *op;
int slot;
int flags;
int wantblink;
switch (blink->bb_status) {
case BIOC_SBBLINK:
wantblink = 1;
break;
case BIOC_SBUNBLINK:
wantblink = 0;
break;
default:
return (EINVAL);
}
rw_enter_read(&sc->sc_lock);
for (slot = 0; slot < sc->sc_nslots; slot++) {
if (sc->sc_slots[slot] == blink->bb_target)
break;
}
rw_exit_read(&sc->sc_lock);
if (slot >= sc->sc_nslots)
return (ENODEV);
op = malloc(sizeof(struct safte_slotop), M_TEMP, 0);
memset(op, 0, sizeof(struct safte_slotop));
op->opcode = SAFTE_WRITE_SLOTOP;
op->slot = slot;
op->flags |= wantblink ? SAFTE_SLOTOP_IDENTIFY : 0;
memset(&cmd, 0, sizeof(cmd));
cmd.opcode = WRITE_BUFFER;
cmd.flags |= SAFTE_WR_MODE;
cmd.length = htobe16(sizeof(struct safte_slotop));
flags = SCSI_DATA_OUT;
#ifndef SCSIDEBUG
flags |= SCSI_SILENT;
#endif
if (cold)
flags |= SCSI_AUTOCONF;
if (scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd,
sizeof(cmd), (u_char *)op, sizeof(struct safte_slotop),
2, 30000, NULL, flags) != 0) {
free(op, M_TEMP);
return (EIO);
}
free(op, M_TEMP);
return (0);
}
#endif /* NBIO > 0 */
int64_t
safte_temp2uK(u_int8_t measured, int celsius)
{
int64_t temp;
temp = (int64_t)measured;
temp += SAFTE_TEMP_OFFSET;
temp *= 1000000; /* convert to micro (mu) degrees */
if (!celsius)
temp = ((temp - 32000000) * 5) / 9; /* convert to Celsius */
temp += 273150000; /* convert to kelvin */
return (temp);
}