diff options
author | ps <ps@FreeBSD.org> | 2003-08-05 19:55:21 +0000 |
---|---|---|
committer | ps <ps@FreeBSD.org> | 2003-08-05 19:55:21 +0000 |
commit | 52bff5229a998fce244a92247317fb6536b7a8d8 (patch) | |
tree | e2e84f0f50ca033d3797a3fad0fe7927745f9df3 /sys/dev/twe/twe.c | |
parent | ad82646deb3641ae38ecc9edcb28cf49eb9c5c6c (diff) | |
download | FreeBSD-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.c | 151 |
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); |