Deleted Added
sdiff udiff text old ( 68877 ) new ( 73050 )
full compact
1/*-
2 * Copyright (c) 2000, 2001 Michael Smith
3 * Copyright (c) 2000 BSDi
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.

--- 8 unchanged lines hidden (view full) ---

19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 * $FreeBSD: head/sys/dev/mly/mly.c 73050 2001-02-25 22:48:34Z msmith $
28 */
29
30#include <sys/param.h>
31#include <sys/systm.h>
32#include <sys/malloc.h>
33#include <sys/kernel.h>
34#include <sys/bus.h>
35#include <sys/conf.h>
36#include <sys/ctype.h>
37#include <sys/ioccom.h>
38#include <sys/stat.h>
39
40#include <machine/bus_memio.h>
41#include <machine/bus.h>
42#include <machine/resource.h>
43#include <sys/rman.h>
44
45#include <cam/scsi/scsi_all.h>
46
47#include <dev/mly/mlyreg.h>
48#include <dev/mly/mlyio.h>
49#include <dev/mly/mlyvar.h>
50#define MLY_DEFINE_TABLES
51#include <dev/mly/mly_tables.h>
52
53static int mly_get_controllerinfo(struct mly_softc *sc);
54static void mly_scan_devices(struct mly_softc *sc);
55static void mly_rescan_btl(struct mly_softc *sc, int bus, int target);
56static void mly_complete_rescan(struct mly_command *mc);

--- 6 unchanged lines hidden (view full) ---

63static void mly_complete_event(struct mly_command *mc);
64static void mly_process_event(struct mly_softc *sc, struct mly_event *me);
65static void mly_periodic(void *data);
66
67static int mly_immediate_command(struct mly_command *mc);
68static int mly_start(struct mly_command *mc);
69static void mly_complete(void *context, int pending);
70
71static void mly_alloc_commands_map(void *arg, bus_dma_segment_t *segs, int nseg, int error);
72static int mly_alloc_commands(struct mly_softc *sc);
73static void mly_map_command(struct mly_command *mc);
74static void mly_unmap_command(struct mly_command *mc);
75
76static int mly_fwhandshake(struct mly_softc *sc);
77
78static void mly_describe_controller(struct mly_softc *sc);
79#ifdef MLY_DEBUG
80static void mly_printstate(struct mly_softc *sc);
81static void mly_print_command(struct mly_command *mc);
82static void mly_print_packet(struct mly_command *mc);
83static void mly_panic(struct mly_softc *sc, char *reason);
84#endif
85void mly_print_controller(int controller);
86
87static d_open_t mly_user_open;
88static d_close_t mly_user_close;
89static d_ioctl_t mly_user_ioctl;
90static int mly_user_command(struct mly_softc *sc, struct mly_user_command *uc);
91static int mly_user_health(struct mly_softc *sc, struct mly_user_health *uh);
92
93#define MLY_CDEV_MAJOR 158
94
95static struct cdevsw mly_cdevsw = {
96 mly_user_open,
97 mly_user_close,
98 noread,
99 nowrite,
100 mly_user_ioctl,
101 nopoll,
102 nommap,
103 nostrategy,
104 "mly",
105 MLY_CDEV_MAJOR,
106 nodump,
107 nopsize,
108 0,
109 -1
110};
111
112/********************************************************************************
113 ********************************************************************************
114 Device Interface
115 ********************************************************************************
116 ********************************************************************************/
117
118/********************************************************************************
119 * Initialise the controller and softc
120 */
121int
122mly_attach(struct mly_softc *sc)
123{
124 int error;
125
126 debug_called(1);
127
128 /*
129 * Initialise per-controller queues.
130 */
131 mly_initq_free(sc);
132 mly_initq_ready(sc);
133 mly_initq_busy(sc);
134 mly_initq_complete(sc);
135
136#if __FreeBSD_version >= 500005
137 /*
138 * Initialise command-completion task.
139 */
140 TASK_INIT(&sc->mly_task_complete, 0, mly_complete, sc);
141#endif
142

--- 4 unchanged lines hidden (view full) ---

147 * Wait for the controller to come ready, handshake with the firmware if required.
148 * This is typically only necessary on platforms where the controller BIOS does not
149 * run.
150 */
151 if ((error = mly_fwhandshake(sc)))
152 return(error);
153
154 /*
155 * Allocate command buffers
156 */
157 if ((error = mly_alloc_commands(sc)))
158 return(error);
159
160 /*
161 * Obtain controller feature information
162 */
163 if ((error = mly_get_controllerinfo(sc)))
164 return(error);
165
166 /*
167 * Get the current event counter for health purposes, populate the initial
168 * health status buffer.
169 */
170 if ((error = mly_get_eventstatus(sc)))
171 return(error);
172
173 /*
174 * Enable memory-mailbox mode

--- 20 unchanged lines hidden (view full) ---

195 /*
196 * Instigate the first status poll immediately. Rescan completions won't
197 * happen until interrupts are enabled, which should still be before
198 * the SCSI subsystem gets to us. (XXX assuming CAM and interrupt-driven
199 * discovery here...)
200 */
201 mly_periodic((void *)sc);
202
203 /*
204 * Create the control device.
205 */
206 sc->mly_dev_t = make_dev(&mly_cdevsw, device_get_unit(sc->mly_dev), UID_ROOT, GID_OPERATOR,
207 S_IRUSR | S_IWUSR, "mly%d", device_get_unit(sc->mly_dev));
208 sc->mly_dev_t->si_drv1 = sc;
209
210 /* enable interrupts now */
211 MLY_UNMASK_INTERRUPTS(sc);
212
213 return(0);
214}
215
216/********************************************************************************
217 * Bring the controller to a state where it can be safely left alone.

--- 177 unchanged lines hidden (view full) ---

395 mly_describe_code(mly_table_device_state, ldi->state));
396 } else if (mc->mc_length == sizeof(*pdi)) {
397 pdi = (struct mly_ioctl_getphysdevinfovalid *)mc->mc_data;
398 bus = pdi->channel;
399 target = pdi->target;
400 sc->mly_btl[bus][target].mb_flags = MLY_BTL_PHYSICAL; /* clears all other flags */
401 sc->mly_btl[bus][target].mb_type = MLY_DEVICE_TYPE_PHYSICAL;
402 sc->mly_btl[bus][target].mb_state = pdi->state;
403 sc->mly_btl[bus][target].mb_speed = pdi->speed;
404 sc->mly_btl[bus][target].mb_width = pdi->width;
405 if (pdi->state != MLY_DEVICE_STATE_UNCONFIGURED)
406 sc->mly_btl[bus][target].mb_flags |= MLY_BTL_PROTECTED;
407 debug(2, "BTL rescan for %d:%d returns %s", bus, target,
408 mly_describe_code(mly_table_device_state, pdi->state));
409 } else {
410 mly_printf(sc, "BTL rescan result corrupted\n");
411 }
412 } else {

--- 52 unchanged lines hidden (view full) ---

465 int error;
466
467 debug_called(1);
468
469 /* build the ioctl and send it */
470 bzero(&mci, sizeof(mci));
471 mci.sub_ioctl = MDACIOCTL_SETMEMORYMAILBOX;
472 /* set buffer addresses */
473 mci.param.setmemorymailbox.command_mailbox_physaddr =
474 sc->mly_mmbox_busaddr + offsetof(struct mly_mmbox, mmm_command);
475 mci.param.setmemorymailbox.status_mailbox_physaddr =
476 sc->mly_mmbox_busaddr + offsetof(struct mly_mmbox, mmm_status);
477 mci.param.setmemorymailbox.health_buffer_physaddr =
478 sc->mly_mmbox_busaddr + offsetof(struct mly_mmbox, mmm_health);
479
480 /* set buffer sizes - abuse of data_size field is revolting */
481 sp = (u_int8_t *)&mci.data_size;
482 sp[0] = ((sizeof(union mly_command_packet) * MLY_MMBOX_COMMANDS) / 1024);
483 sp[1] = (sizeof(union mly_status_packet) * MLY_MMBOX_STATUS) / 1024;
484 mci.param.setmemorymailbox.health_buffer_size = sizeof(union mly_health_region) / 1024;
485
486 debug(1, "memory mailbox at %p (0x%llx/%d 0x%llx/%d 0x%llx/%d", sc->mly_mmbox,
487 mci.param.setmemorymailbox.command_mailbox_physaddr, sp[0],
488 mci.param.setmemorymailbox.status_mailbox_physaddr, sp[1],
489 mci.param.setmemorymailbox.health_buffer_physaddr,
490 mci.param.setmemorymailbox.health_buffer_size);
491
492 if ((error = mly_ioctl(sc, &mci, NULL, 0, &status, NULL, NULL)))
493 return(error);
494 if (status != 0)
495 return(EIO);
496 sc->mly_state |= MLY_STATE_MMBOX_ACTIVE;
497 debug(1, "memory mailbox active");
498 return(0);

--- 338 unchanged lines hidden (view full) ---

837
838 /* spinning at splcam is ugly, but we're only used during controller init */
839 s = splcam();
840 if ((error = mly_start(mc)))
841 return(error);
842
843 if (sc->mly_state & MLY_STATE_INTERRUPTS_ON) {
844 /* sleep on the command */
845 while(!(mc->mc_flags & MLY_CMD_COMPLETE)) {
846 tsleep(mc, PRIBIO, "mlywait", 0);
847 }
848 } else {
849 /* spin and collect status while we do */
850 while(!(mc->mc_flags & MLY_CMD_COMPLETE)) {
851 mly_done(mc->mc_sc);
852 }
853 }
854 splx(s);
855 return(0);
856}
857
858/********************************************************************************
859 * Start as much queued I/O as possible on the controller
860 */

--- 35 unchanged lines hidden (view full) ---

896{
897 struct mly_softc *sc = mc->mc_sc;
898 union mly_command_packet *pkt;
899 int s;
900
901 debug_called(2);
902
903 /*
904 * Set the command up for delivery to the controller.
905 */
906 mly_map_command(mc);
907 mc->mc_packet->generic.command_id = mc->mc_slot;
908
909 s = splcam();
910
911 /*
912 * Do we have to use the hardware mailbox?
913 */
914 if (!(sc->mly_state & MLY_STATE_MMBOX_ACTIVE)) {
915 /*
916 * Check to see if the controller is ready for us.
917 */
918 if (MLY_IDBR_TRUE(sc, MLY_HM_CMDSENT)) {
919 splx(s);
920 return(EBUSY);
921 }
922 mc->mc_flags |= MLY_CMD_BUSY;
923
924 /*
925 * It's ready, send the command.
926 */
927 MLY_SET_MBOX(sc, sc->mly_command_mailbox, &mc->mc_packetphys);
928 MLY_SET_REG(sc, sc->mly_idbr, MLY_HM_CMDSENT);
929
930 } else { /* use memory-mailbox mode */
931
932 pkt = &sc->mly_mmbox->mmm_command[sc->mly_mmbox_command_index];
933
934 /* check to see if the next index is free yet */
935 if (pkt->mmbox.flag != 0) {
936 splx(s);
937 return(EBUSY);
938 }
939 mc->mc_flags |= MLY_CMD_BUSY;
940
941 /* copy in new command */
942 bcopy(mc->mc_packet->mmbox.data, pkt->mmbox.data, sizeof(pkt->mmbox.data));
943 /* barrier to ensure completion of previous write before we write the flag */
944 bus_space_barrier(NULL, NULL, 0, 0, BUS_SPACE_BARRIER_WRITE); /* tag/handle? */
945 /* copy flag last */
946 pkt->mmbox.flag = mc->mc_packet->mmbox.flag;
947 /* barrier to ensure completion of previous write before we notify the controller */
948 bus_space_barrier(NULL, NULL, 0, 0, BUS_SPACE_BARRIER_WRITE); /* tag/handle */
949
950 /* signal controller, update index */
951 MLY_SET_REG(sc, sc->mly_idbr, MLY_AM_CMDSENT);
952 sc->mly_mmbox_command_index = (sc->mly_mmbox_command_index + 1) % MLY_MMBOX_COMMANDS;
953 }
954
955 mly_enqueue_busy(mc);
956 splx(s);
957 return(0);
958}
959
960/********************************************************************************
961 * Pick up command status from the controller, schedule a completion event
962 */
963void

--- 6 unchanged lines hidden (view full) ---

970
971 s = splcam();
972 worked = 0;
973
974 /* pick up hardware-mailbox commands */
975 if (MLY_ODBR_TRUE(sc, MLY_HM_STSREADY)) {
976 slot = MLY_GET_REG2(sc, sc->mly_status_mailbox);
977 if (slot < MLY_SLOT_MAX) {
978 mc = &sc->mly_command[slot - MLY_SLOT_START];
979 mc->mc_status = MLY_GET_REG(sc, sc->mly_status_mailbox + 2);
980 mc->mc_sense = MLY_GET_REG(sc, sc->mly_status_mailbox + 3);
981 mc->mc_resid = MLY_GET_REG4(sc, sc->mly_status_mailbox + 4);
982 mly_remove_busy(mc);
983 mc->mc_flags &= ~MLY_CMD_BUSY;
984 mly_enqueue_complete(mc);
985 worked = 1;
986 } else {
987 /* slot 0xffff may mean "extremely bogus command" */
988 mly_printf(sc, "got HM completion for illegal slot %u\n", slot);
989 }
990 /* unconditionally acknowledge status */
991 MLY_SET_REG(sc, sc->mly_odbr, MLY_HM_STSREADY);
992 MLY_SET_REG(sc, sc->mly_idbr, MLY_HM_STSACK);
993 }

--- 5 unchanged lines hidden (view full) ---

999
1000 /* check for more status */
1001 if (sp->mmbox.flag == 0)
1002 break;
1003
1004 /* get slot number */
1005 slot = sp->status.command_id;
1006 if (slot < MLY_SLOT_MAX) {
1007 mc = &sc->mly_command[slot - MLY_SLOT_START];
1008 mc->mc_status = sp->status.status;
1009 mc->mc_sense = sp->status.sense_length;
1010 mc->mc_resid = sp->status.residue;
1011 mly_remove_busy(mc);
1012 mc->mc_flags &= ~MLY_CMD_BUSY;
1013 mly_enqueue_complete(mc);
1014 worked = 1;
1015 } else {
1016 /* slot 0xffff may mean "extremely bogus command" */
1017 mly_printf(sc, "got AM completion for illegal slot %u at %d\n",
1018 slot, sc->mly_mmbox_status_index);
1019 }
1020
1021 /* clear and move to next index */
1022 sp->mmbox.flag = 0;
1023 sc->mly_mmbox_status_index = (sc->mly_mmbox_status_index + 1) % MLY_MMBOX_STATUS;
1024 }
1025 /* acknowledge that we have collected status value(s) */
1026 MLY_SET_REG(sc, sc->mly_odbr, MLY_AM_STSREADY);
1027 }
1028
1029 splx(s);

--- 18 unchanged lines hidden (view full) ---

1048 void (* mc_complete)(struct mly_command *mc);
1049
1050
1051 debug_called(2);
1052
1053 /*
1054 * Spin pulling commands off the completed queue and processing them.
1055 */
1056 while ((mc = mly_dequeue_complete(sc)) != NULL) {
1057
1058 /*
1059 * Free controller resources, mark command complete.
1060 *
1061 * Note that as soon as we mark the command complete, it may be freed
1062 * out from under us, so we need to save the mc_complete field in
1063 * order to later avoid dereferencing mc. (We would not expect to
1064 * have a polling/sleeping consumer with mc_complete != NULL).
1065 */
1066 mly_unmap_command(mc);
1067 mc_complete = mc->mc_complete;
1068 mc->mc_flags |= MLY_CMD_COMPLETE;
1069
1070 /*
1071 * Call completion handler or wake up sleeping consumer.
1072 */
1073 if (mc_complete != NULL) {
1074 mc_complete(mc);
1075 } else {
1076 wakeup(mc);

--- 15 unchanged lines hidden (view full) ---

1092 * a while just to check up on it. While a filesystem is mounted, or I/O is
1093 * active this isn't really an issue.
1094 */
1095 if (sc->mly_mmbox->mmm_health.status.change_counter != sc->mly_event_change) {
1096 sc->mly_event_change = sc->mly_mmbox->mmm_health.status.change_counter;
1097 debug(1, "event change %d, event status update, %d -> %d", sc->mly_event_change,
1098 sc->mly_event_waiting, sc->mly_mmbox->mmm_health.status.next_event);
1099 sc->mly_event_waiting = sc->mly_mmbox->mmm_health.status.next_event;
1100
1101 /* wake up anyone that might be interested in this */
1102 wakeup(&sc->mly_event_change);
1103 }
1104 if (sc->mly_event_counter != sc->mly_event_waiting)
1105 mly_fetch_event(sc);
1106}
1107
1108/********************************************************************************
1109 ********************************************************************************
1110 Command Buffer Management
1111 ********************************************************************************
1112 ********************************************************************************/
1113
1114/********************************************************************************
1115 * Allocate a command.
1116 */
1117int
1118mly_alloc_command(struct mly_softc *sc, struct mly_command **mcp)
1119{
1120 struct mly_command *mc;
1121
1122 debug_called(3);
1123
1124 if ((mc = mly_dequeue_free(sc)) == NULL)
1125 return(ENOMEM);
1126
1127 *mcp = mc;
1128 return(0);
1129}
1130
1131/********************************************************************************
1132 * Release a command back to the freelist.
1133 */
1134void
1135mly_release_command(struct mly_command *mc)
1136{
1137 debug_called(3);
1138
1139 /*
1140 * Fill in parts of the command that may cause confusion if
1141 * a consumer doesn't when we are later allocated.
1142 */
1143 mc->mc_data = NULL;
1144 mc->mc_flags = 0;
1145 mc->mc_complete = NULL;
1146 mc->mc_private = NULL;
1147
1148 /*
1149 * By default, we set up to overwrite the command packet with
1150 * sense information.
1151 */
1152 mc->mc_packet->generic.sense_buffer_address = mc->mc_packetphys;
1153 mc->mc_packet->generic.maximum_sense_size = sizeof(union mly_command_packet);
1154
1155 mly_enqueue_free(mc);
1156}
1157
1158/********************************************************************************
1159 * Map helper for command allocation.
1160 */
1161static void
1162mly_alloc_commands_map(void *arg, bus_dma_segment_t *segs, int nseg, int error)
1163{
1164 struct mly_softc *sc = (struct mly_softc *)arg
1165
1166 debug_called(2);
1167
1168 sc->mly_packetphys = segs[0].ds_addr;
1169}
1170
1171/********************************************************************************
1172 * Allocate and initialise command and packet structures.
1173 */
1174static int
1175mly_alloc_commands(struct mly_softc *sc)
1176{
1177 struct mly_command *mc;
1178 int i;
1179
1180 /*
1181 * Allocate enough space for all the command packets in one chunk and
1182 * map them permanently into controller-visible space.
1183 */
1184 if (bus_dmamem_alloc(sc->mly_packet_dmat, (void **)&sc->mly_packet,
1185 BUS_DMA_NOWAIT, &sc->mly_packetmap)) {
1186 return(ENOMEM);
1187 }
1188 bus_dmamap_load(sc->mly_packet_dmat, sc->mly_packetmap, sc->mly_packet,
1189 MLY_MAXCOMMANDS * sizeof(union mly_command_packet),
1190 mly_alloc_commands_map, sc, 0);
1191
1192 for (i = 0; i < MLY_MAXCOMMANDS; i++) {
1193 mc = &sc->mly_command[i];
1194 bzero(mc, sizeof(*mc));
1195 mc->mc_sc = sc;
1196 mc->mc_slot = MLY_SLOT_START + i;
1197 mc->mc_packet = sc->mly_packet + i;
1198 mc->mc_packetphys = sc->mly_packetphys + (i * sizeof(union mly_command_packet));
1199 if (!bus_dmamap_create(sc->mly_buffer_dmat, 0, &mc->mc_datamap))
1200 mly_release_command(mc);
1201 }
1202 return(0);
1203}
1204
1205/********************************************************************************
1206 * Command-mapping helper function - populate this command's s/g table
1207 * with the s/g entries for its data.
1208 */
1209static void
1210mly_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error)
1211{
1212 struct mly_command *mc = (struct mly_command *)arg;
1213 struct mly_softc *sc = mc->mc_sc;
1214 struct mly_command_generic *gen = &(mc->mc_packet->generic);
1215 struct mly_sg_entry *sg;
1216 int i, tabofs;
1217
1218 debug_called(3);
1219
1220 /* can we use the transfer structure directly? */
1221 if (nseg <= 2) {
1222 sg = &gen->transfer.direct.sg[0];
1223 gen->command_control.extended_sg_table = 0;
1224 } else {
1225 tabofs = ((mc->mc_slot - MLY_SLOT_START) * MLY_MAXSGENTRIES);
1226 sg = sc->mly_sg_table + tabofs;
1227 gen->transfer.indirect.entries[0] = nseg;
1228 gen->transfer.indirect.table_physaddr[0] = sc->mly_sg_busaddr + (tabofs * sizeof(struct mly_sg_entry));
1229 gen->command_control.extended_sg_table = 1;
1230 }
1231
1232 /* copy the s/g table */
1233 for (i = 0; i < nseg; i++) {

--- 250 unchanged lines hidden (view full) ---

1484 */
1485static void
1486mly_print_command(struct mly_command *mc)
1487{
1488 struct mly_softc *sc = mc->mc_sc;
1489
1490 mly_printf(sc, "COMMAND @ %p\n", mc);
1491 mly_printf(sc, " slot %d\n", mc->mc_slot);
1492 mly_printf(sc, " status 0x%x\n", mc->mc_status);
1493 mly_printf(sc, " sense len %d\n", mc->mc_sense);
1494 mly_printf(sc, " resid %d\n", mc->mc_resid);
1495 mly_printf(sc, " packet %p/0x%llx\n", mc->mc_packet, mc->mc_packetphys);
1496 if (mc->mc_packet != NULL)
1497 mly_print_packet(mc);
1498 mly_printf(sc, " data %p/%d\n", mc->mc_data, mc->mc_length);
1499 mly_printf(sc, " flags %b\n", mc->mc_flags, "\20\1busy\2complete\3slotted\4mapped\5datain\6dataout\n");
1500 mly_printf(sc, " complete %p\n", mc->mc_complete);
1501 mly_printf(sc, " private %p\n", mc->mc_private);
1502}
1503
1504/********************************************************************************
1505 * Print a command packet
1506 */
1507static void

--- 161 unchanged lines hidden (view full) ---

1669 */
1670static void
1671mly_panic(struct mly_softc *sc, char *reason)
1672{
1673 mly_printstate(sc);
1674 panic(reason);
1675}
1676#endif
1677
1678/********************************************************************************
1679 * Print queue statistics, callable from DDB.
1680 */
1681void
1682mly_print_controller(int controller)
1683{
1684 struct mly_softc *sc;
1685
1686 if ((sc = devclass_get_softc(devclass_find("mly"), controller)) == NULL) {
1687 printf("mly: controller %d invalid\n", controller);
1688 } else {
1689 device_printf(sc->mly_dev, "queue curr max\n");
1690 device_printf(sc->mly_dev, "free %04d/%04d\n",
1691 sc->mly_qstat[MLYQ_FREE].q_length, sc->mly_qstat[MLYQ_FREE].q_max);
1692 device_printf(sc->mly_dev, "ready %04d/%04d\n",
1693 sc->mly_qstat[MLYQ_READY].q_length, sc->mly_qstat[MLYQ_READY].q_max);
1694 device_printf(sc->mly_dev, "busy %04d/%04d\n",
1695 sc->mly_qstat[MLYQ_BUSY].q_length, sc->mly_qstat[MLYQ_BUSY].q_max);
1696 device_printf(sc->mly_dev, "complete %04d/%04d\n",
1697 sc->mly_qstat[MLYQ_COMPLETE].q_length, sc->mly_qstat[MLYQ_COMPLETE].q_max);
1698 }
1699}
1700
1701
1702/********************************************************************************
1703 ********************************************************************************
1704 Control device interface
1705 ********************************************************************************
1706 ********************************************************************************/
1707
1708/********************************************************************************
1709 * Accept an open operation on the control device.
1710 */
1711static int
1712mly_user_open(dev_t dev, int flags, int fmt, struct proc *p)
1713{
1714 int unit = minor(dev);
1715 struct mly_softc *sc = devclass_get_softc(devclass_find("mly"), unit);
1716
1717 sc->mly_state |= MLY_STATE_OPEN;
1718 return(0);
1719}
1720
1721/********************************************************************************
1722 * Accept the last close on the control device.
1723 */
1724static int
1725mly_user_close(dev_t dev, int flags, int fmt, struct proc *p)
1726{
1727 int unit = minor(dev);
1728 struct mly_softc *sc = devclass_get_softc(devclass_find("mly"), unit);
1729
1730 sc->mly_state &= ~MLY_STATE_OPEN;
1731 return (0);
1732}
1733
1734/********************************************************************************
1735 * Handle controller-specific control operations.
1736 */
1737static int
1738mly_user_ioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct proc *p)
1739{
1740 struct mly_softc *sc = (struct mly_softc *)dev->si_drv1;
1741 struct mly_user_command *uc = (struct mly_user_command *)addr;
1742 struct mly_user_health *uh = (struct mly_user_health *)addr;
1743
1744 switch(cmd) {
1745 case MLYIO_COMMAND:
1746 return(mly_user_command(sc, uc));
1747 case MLYIO_HEALTH:
1748 return(mly_user_health(sc, uh));
1749 default:
1750 return(ENOIOCTL);
1751 }
1752}
1753
1754/********************************************************************************
1755 * Execute a command passed in from userspace.
1756 *
1757 * The control structure contains the actual command for the controller, as well
1758 * as the user-space data pointer and data size, and an optional sense buffer
1759 * size/pointer. On completion, the data size is adjusted to the command
1760 * residual, and the sense buffer size to the size of the returned sense data.
1761 *
1762 */
1763static int
1764mly_user_command(struct mly_softc *sc, struct mly_user_command *uc)
1765{
1766 struct mly_command *mc;
1767 int error, s;
1768
1769 /* allocate a command */
1770 if (mly_alloc_command(sc, &mc)) {
1771 error = ENOMEM;
1772 goto out; /* XXX Linux version will wait for a command */
1773 }
1774
1775 /* handle data size/direction */
1776 mc->mc_length = (uc->DataTransferLength >= 0) ? uc->DataTransferLength : -uc->DataTransferLength;
1777 if (mc->mc_length > 0) {
1778 if ((mc->mc_data = malloc(mc->mc_length, M_DEVBUF, M_NOWAIT)) == NULL) {
1779 error = ENOMEM;
1780 goto out;
1781 }
1782 }
1783 if (uc->DataTransferLength > 0) {
1784 mc->mc_flags |= MLY_CMD_DATAIN;
1785 bzero(mc->mc_data, mc->mc_length);
1786 }
1787 if (uc->DataTransferLength < 0) {
1788 mc->mc_flags |= MLY_CMD_DATAOUT;
1789 if ((error = copyin(uc->DataTransferBuffer, mc->mc_data, mc->mc_length)) != 0)
1790 goto out;
1791 }
1792
1793 /* copy the controller command */
1794 bcopy(&uc->CommandMailbox, mc->mc_packet, sizeof(uc->CommandMailbox));
1795
1796 /* clear command completion handler so that we get woken up */
1797 mc->mc_complete = NULL;
1798
1799 /* execute the command */
1800 s = splcam();
1801 mly_requeue_ready(mc);
1802 mly_startio(sc);
1803 while (!(mc->mc_flags & MLY_CMD_COMPLETE))
1804 tsleep(mc, PRIBIO, "mlyioctl", 0);
1805 splx(s);
1806
1807 /* return the data to userspace */
1808 if (uc->DataTransferLength > 0)
1809 if ((error = copyout(mc->mc_data, uc->DataTransferBuffer, mc->mc_length)) != 0)
1810 goto out;
1811
1812 /* return the sense buffer to userspace */
1813 if ((uc->RequestSenseLength > 0) && (mc->mc_sense > 0)) {
1814 if ((error = copyout(mc->mc_packet, uc->RequestSenseBuffer,
1815 min(uc->RequestSenseLength, mc->mc_sense))) != 0)
1816 goto out;
1817 }
1818
1819 /* return command results to userspace (caller will copy out) */
1820 uc->DataTransferLength = mc->mc_resid;
1821 uc->RequestSenseLength = min(uc->RequestSenseLength, mc->mc_sense);
1822 uc->CommandStatus = mc->mc_status;
1823 error = 0;
1824
1825 out:
1826 if (mc->mc_data != NULL)
1827 free(mc->mc_data, M_DEVBUF);
1828 if (mc != NULL)
1829 mly_release_command(mc);
1830 return(error);
1831}
1832
1833/********************************************************************************
1834 * Return health status to userspace. If the health change index in the user
1835 * structure does not match that currently exported by the controller, we
1836 * return the current status immediately. Otherwise, we block until either
1837 * interrupted or new status is delivered.
1838 */
1839static int
1840mly_user_health(struct mly_softc *sc, struct mly_user_health *uh)
1841{
1842 struct mly_health_status mh;
1843 int error, s;
1844
1845 /* fetch the current health status from userspace */
1846 if ((error = copyin(uh->HealthStatusBuffer, &mh, sizeof(mh))) != 0)
1847 return(error);
1848
1849 /* spin waiting for a status update */
1850 s = splcam();
1851 error = EWOULDBLOCK;
1852 while ((error != 0) && (sc->mly_event_change == mh.change_counter))
1853 error = tsleep(&sc->mly_event_change, PRIBIO | PCATCH, "mlyhealth", 0);
1854 splx(s);
1855
1856 /* copy the controller's health status buffer out (there is a race here if it changes again) */
1857 error = copyout(&sc->mly_mmbox->mmm_health.status, uh->HealthStatusBuffer,
1858 sizeof(uh->HealthStatusBuffer));
1859 return(error);
1860}