summaryrefslogtreecommitdiffstats
path: root/sys/dev/twe/twe.c
diff options
context:
space:
mode:
authorps <ps@FreeBSD.org>2003-08-05 19:55:21 +0000
committerps <ps@FreeBSD.org>2003-08-05 19:55:21 +0000
commit52bff5229a998fce244a92247317fb6536b7a8d8 (patch)
treee2e84f0f50ca033d3797a3fad0fe7927745f9df3 /sys/dev/twe/twe.c
parentad82646deb3641ae38ecc9edcb28cf49eb9c5c6c (diff)
downloadFreeBSD-src-52bff5229a998fce244a92247317fb6536b7a8d8.zip
FreeBSD-src-52bff5229a998fce244a92247317fb6536b7a8d8.tar.gz
Properly support the 3ware generic API.
- Build SGL's for ATA_PASSTHROUGH commands - Fallback to using the sgl_offset when the opcode is unknown for building SGL's/ - Add ioctl calls for adding and removing units. - Define previously undefined AEN's - Allocate memory for the ioctl payload in multiples of 512bytes. MFC after: 1 week
Diffstat (limited to 'sys/dev/twe/twe.c')
-rw-r--r--sys/dev/twe/twe.c151
1 files changed, 92 insertions, 59 deletions
diff --git a/sys/dev/twe/twe.c b/sys/dev/twe/twe.c
index 43df8e9..e2f5ff1 100644
--- a/sys/dev/twe/twe.c
+++ b/sys/dev/twe/twe.c
@@ -60,6 +60,8 @@ static int twe_wait_request(struct twe_request *tr);
static int twe_immediate_request(struct twe_request *tr);
static void twe_completeio(struct twe_request *tr);
static void twe_reset(struct twe_softc *sc);
+static void twe_add_unit(struct twe_softc *sc, int unit);
+static void twe_del_unit(struct twe_softc *sc, int unit);
/*
* Command I/O to controller.
@@ -189,18 +191,17 @@ twe_setup(struct twe_softc *sc)
return(0);
}
-/********************************************************************************
- * Locate disk devices and attach children to them.
- */
-void
-twe_init(struct twe_softc *sc)
+static void
+twe_add_unit(struct twe_softc *sc, int unit)
{
struct twe_drive *dr;
- int i, table;
+ int table;
u_int16_t dsize;
- TWE_Param *drives, *param;
+ TWE_Param *drives = NULL, *param = NULL;
TWE_Unit_Descriptor *ud;
+ if (unit < 0 || unit > TWE_MAX_UNITS)
+ return;
/*
* The controller is in a safe state, so try to find drives attached to it.
@@ -210,52 +211,76 @@ twe_init(struct twe_softc *sc)
twe_printf(sc, "can't detect attached units\n");
return;
}
-
- /*
- * For each detected unit, create a child device.
- */
- for (i = 0, dr = &sc->twe_drive[0]; i < TWE_MAX_UNITS; i++, dr++) {
- /* check that the drive is online */
- if (!(drives->data[i] & TWE_PARAM_UNITSTATUS_Online))
- continue;
+ dr = &sc->twe_drive[unit];
+ /* check that the drive is online */
+ if (!(drives->data[unit] & TWE_PARAM_UNITSTATUS_Online))
+ goto out;
- table = TWE_PARAM_UNITINFO + i;
+ table = TWE_PARAM_UNITINFO + unit;
- if (twe_get_param_4(sc, table, TWE_PARAM_UNITINFO_Capacity, &dr->td_size)) {
- twe_printf(sc, "error fetching capacity for unit %d\n", i);
- continue;
- }
- if (twe_get_param_1(sc, table, TWE_PARAM_UNITINFO_Status, &dr->td_state)) {
- twe_printf(sc, "error fetching state for unit %d\n", i);
- continue;
- }
- if (twe_get_param_2(sc, table, TWE_PARAM_UNITINFO_DescriptorSize, &dsize)) {
- twe_printf(sc, "error fetching descriptor size for unit %d\n", i);
- continue;
- }
- if ((param = twe_get_param(sc, table, TWE_PARAM_UNITINFO_Descriptor, dsize - 3, NULL)) == NULL) {
- twe_printf(sc, "error fetching descriptor for unit %d\n", i);
- continue;
- }
- ud = (TWE_Unit_Descriptor *)param->data;
- dr->td_type = ud->configuration;
+ if (twe_get_param_4(sc, table, TWE_PARAM_UNITINFO_Capacity, &dr->td_size)) {
+ twe_printf(sc, "error fetching capacity for unit %d\n", unit);
+ goto out;
+ }
+ if (twe_get_param_1(sc, table, TWE_PARAM_UNITINFO_Status, &dr->td_state)) {
+ twe_printf(sc, "error fetching state for unit %d\n", unit);
+ goto out;
+ }
+ if (twe_get_param_2(sc, table, TWE_PARAM_UNITINFO_DescriptorSize, &dsize)) {
+ twe_printf(sc, "error fetching descriptor size for unit %d\n", unit);
+ goto out;
+ }
+ if ((param = twe_get_param(sc, table, TWE_PARAM_UNITINFO_Descriptor, dsize - 3, NULL)) == NULL) {
+ twe_printf(sc, "error fetching descriptor for unit %d\n", unit);
+ goto out;
+ }
+ ud = (TWE_Unit_Descriptor *)param->data;
+ dr->td_type = ud->configuration;
+
+ /* build synthetic geometry as per controller internal rules */
+ if (dr->td_size > 0x200000) {
+ dr->td_heads = 255;
+ dr->td_sectors = 63;
+ } else {
+ dr->td_heads = 64;
+ dr->td_sectors = 32;
+ }
+ dr->td_cylinders = dr->td_size / (dr->td_heads * dr->td_sectors);
+ dr->td_unit = unit;
+
+ twe_attach_drive(sc, dr);
+
+out:
+ if (param != NULL)
free(param, M_DEVBUF);
+ if (drives != NULL)
+ free(drives, M_DEVBUF);
+}
- /* build synthetic geometry as per controller internal rules */
- if (dr->td_size > 0x200000) {
- dr->td_heads = 255;
- dr->td_sectors = 63;
- } else {
- dr->td_heads = 64;
- dr->td_sectors = 32;
- }
- dr->td_cylinders = dr->td_size / (dr->td_heads * dr->td_sectors);
- dr->td_unit = i;
+static void
+twe_del_unit(struct twe_softc *sc, int unit)
+{
- twe_attach_drive(sc, dr);
- }
- free(drives, M_DEVBUF);
+ if (unit < 0 || unit > TWE_MAX_UNITS)
+ return;
+
+ twe_detach_drive(sc, unit);
+}
+
+/********************************************************************************
+ * Locate disk devices and attach children to them.
+ */
+void
+twe_init(struct twe_softc *sc)
+{
+ int i;
+
+ /*
+ * Scan for drives
+ */
+ for (i = 0; i < TWE_MAX_UNITS; i++)
+ twe_add_unit(sc, i);
/*
* Initialise connection with controller.
@@ -447,6 +472,7 @@ twe_ioctl(struct twe_softc *sc, int cmd, void *addr)
{
struct twe_usercommand *tu = (struct twe_usercommand *)addr;
struct twe_paramcommand *tp = (struct twe_paramcommand *)addr;
+ struct twe_drivecommand *td = (struct twe_drivecommand *)addr;
union twe_statrequest *ts = (union twe_statrequest *)addr;
TWE_Param *param;
void *data;
@@ -460,10 +486,8 @@ twe_ioctl(struct twe_softc *sc, int cmd, void *addr)
/* handle a command from userspace */
case TWEIO_COMMAND:
/* get a request */
- if (twe_get_request(sc, &tr)) {
- error = EBUSY;
- goto cmd_done;
- }
+ while (twe_get_request(sc, &tr))
+ tsleep(NULL, PPAUSE, "twioctl", hz);
/*
* Save the command's request ID, copy the user-supplied command in,
@@ -473,14 +497,17 @@ twe_ioctl(struct twe_softc *sc, int cmd, void *addr)
bcopy(&tu->tu_command, &tr->tr_command, sizeof(TWE_Command));
tr->tr_command.generic.request_id = srid;
- /* if there's a data buffer, allocate and copy it in */
- tr->tr_length = tu->tu_size;
+ /*
+ * if there's a data buffer, allocate and copy it in.
+ * Must be in multipled of 512 bytes.
+ */
+ tr->tr_length = (tu->tu_size + 511) & ~511;
if (tr->tr_length > 0) {
if ((tr->tr_data = malloc(tr->tr_length, M_DEVBUF, M_WAITOK)) == NULL) {
error = ENOMEM;
goto cmd_done;
}
- if ((error = copyin(tu->tu_data, tr->tr_data, tr->tr_length)) != 0)
+ if ((error = copyin(tu->tu_data, tr->tr_data, tu->tu_size)) != 0)
goto cmd_done;
tr->tr_flags |= TWE_CMD_DATAIN | TWE_CMD_DATAOUT;
}
@@ -494,7 +521,7 @@ twe_ioctl(struct twe_softc *sc, int cmd, void *addr)
/* if there was a data buffer, copy it out */
if (tr->tr_length > 0)
- error = copyout(tr->tr_data, tu->tu_data, tr->tr_length);
+ error = copyout(tr->tr_data, tu->tu_data, tu->tu_size);
cmd_done:
/* free resources */
@@ -526,14 +553,12 @@ twe_ioctl(struct twe_softc *sc, int cmd, void *addr)
/* poll for an AEN */
case TWEIO_AEN_POLL:
*arg = twe_dequeue_aen(sc);
- if (*arg == -1)
- error = ENOENT;
break;
/* wait for another AEN to show up */
case TWEIO_AEN_WAIT:
s = splbio();
- while ((*arg = twe_dequeue_aen(sc)) == -1) {
+ while ((*arg = twe_dequeue_aen(sc)) == TWE_AEN_QUEUE_EMPTY) {
error = tsleep(&sc->twe_aen_queue, PRIBIO | PCATCH, "tweaen", 0);
if (error == EINTR)
break;
@@ -573,6 +598,14 @@ twe_ioctl(struct twe_softc *sc, int cmd, void *addr)
twe_reset(sc);
break;
+ case TWEIO_ADD_UNIT:
+ twe_add_unit(sc, td->td_unit);
+ break;
+
+ case TWEIO_DEL_UNIT:
+ twe_del_unit(sc, td->td_unit);
+ break;
+
/* XXX implement ATA PASSTHROUGH */
/* nothing we understand */
@@ -1394,7 +1427,7 @@ twe_dequeue_aen(struct twe_softc *sc)
debug_called(4);
if (sc->twe_aen_tail == sc->twe_aen_head) {
- result = -1;
+ result = TWE_AEN_QUEUE_EMPTY;
} else {
result = sc->twe_aen_queue[sc->twe_aen_tail];
sc->twe_aen_tail = ((sc->twe_aen_tail + 1) % TWE_Q_LENGTH);
OpenPOWER on IntegriCloud