Commit | Line | Data |
---|---|---|
92e67171 | 1 | /* up.c 6.1 83/07/29 */ |
258a5c40 | 2 | |
0839bdeb SL |
3 | /* |
4 | * UNIBUS peripheral standalone driver | |
5 | * with ECC correction and bad block forwarding. | |
6 | * Also supports header operation and write | |
7 | * check for data and/or header. | |
8 | */ | |
258a5c40 SL |
9 | #include "../h/param.h" |
10 | #include "../h/inode.h" | |
11 | #include "../h/fs.h" | |
12 | #include "../h/dkbad.h" | |
13 | #include "../h/vmmac.h" | |
14 | ||
15 | #include "../vax/pte.h" | |
16 | #include "../vaxuba/upreg.h" | |
17 | #include "../vaxuba/ubareg.h" | |
18 | ||
0839bdeb | 19 | #include "saio.h" |
258a5c40 SL |
20 | #include "savax.h" |
21 | ||
b8ca3ab9 HS |
22 | #define MAXBADDESC 126 /* max number of bad sectors recorded */ |
23 | #define SECTSIZ 512 /* sector size in bytes */ | |
24 | #define HDRSIZ 4 /* number of bytes in sector header */ | |
dda2842d | 25 | |
31fa9244 | 26 | #define MAXECC 5 /* max # bad bits allowed on ecc w/ F_ECCLM */ |
b8ca3ab9 | 27 | |
258a5c40 | 28 | u_short ubastd[] = { 0776700 }; |
0839bdeb | 29 | |
dda2842d SL |
30 | char up_gottype[MAXNUBA*8]; |
31 | char up_type[MAXNUBA*8]; | |
b4736392 | 32 | extern struct st upst[]; |
0839bdeb | 33 | |
dda2842d SL |
34 | struct dkbad upbad[MAXNUBA*8]; /* bad sector table */ |
35 | int sectsiz; /* real sector size */ | |
36 | int updebug[MAXNUBA*8]; | |
37 | #define UPF_BSEDEBUG 01 /* debugging bad sector forwarding */ | |
38 | #define UPF_ECCDEBUG 02 /* debugging ecc correction */ | |
39 | ||
258a5c40 SL |
40 | u_char up_offset[16] = { |
41 | UPOF_P400, UPOF_M400, UPOF_P400, UPOF_M400, | |
42 | UPOF_P800, UPOF_M800, UPOF_P800, UPOF_M800, | |
43 | UPOF_P1200, UPOF_M1200, UPOF_P1200, UPOF_M1200, | |
44 | 0, 0, 0, 0 | |
45 | }; | |
46 | ||
47 | upopen(io) | |
48 | register struct iob *io; | |
49 | { | |
b8ca3ab9 | 50 | register unit = io->i_unit; |
0839bdeb | 51 | register struct updevice *upaddr; |
31fa9244 | 52 | register struct st *st; |
258a5c40 | 53 | |
b4736392 | 54 | if (io->i_boff < 0 || io->i_boff > 7) |
0839bdeb | 55 | _stop("up bad unit"); |
b8ca3ab9 | 56 | upaddr = (struct updevice *)ubamem(unit, ubastd[0]); |
3ab40097 | 57 | while ((upaddr->upcs1 & UP_DVA) == 0) |
258a5c40 | 58 | ; |
b8ca3ab9 | 59 | if (up_gottype[unit] == 0) { |
0839bdeb SL |
60 | register int i; |
61 | struct iob tio; | |
62 | ||
31fa9244 SL |
63 | up_type[unit] = upmaptype(unit, upaddr); |
64 | if (up_type[unit] < 0) | |
0839bdeb | 65 | _stop("unknown drive type"); |
31fa9244 | 66 | st = &upst[up_type[unit]]; |
b4736392 SL |
67 | if (st->off[io->i_boff] == -1) |
68 | _stop("up bad unit"); | |
0839bdeb | 69 | /* |
dda2842d | 70 | * Read in the bad sector table. |
0839bdeb SL |
71 | */ |
72 | tio = *io; | |
73 | tio.i_bn = st->nspc * st->ncyl - st->nsect; | |
258a5c40 | 74 | tio.i_ma = (char *)&upbad[tio.i_unit]; |
960ade39 | 75 | tio.i_cc = sizeof (struct dkbad); |
0839bdeb SL |
76 | tio.i_flgs |= F_RDDATA; |
77 | for (i = 0; i < 5; i++) { | |
960ade39 | 78 | if (upstrategy(&tio, READ) == sizeof (struct dkbad)) |
0839bdeb | 79 | break; |
258a5c40 SL |
80 | tio.i_bn += 2; |
81 | } | |
82 | if (i == 5) { | |
0839bdeb | 83 | printf("Unable to read bad sector table\n"); |
b8ca3ab9 HS |
84 | for (i = 0; i < MAXBADDESC; i++) { |
85 | upbad[unit].bt_bad[i].bt_cyl = -1; | |
86 | upbad[unit].bt_bad[i].bt_trksec = -1; | |
258a5c40 SL |
87 | } |
88 | } | |
b8ca3ab9 | 89 | up_gottype[unit] = 1; |
258a5c40 | 90 | } |
258a5c40 | 91 | io->i_boff = st->off[io->i_boff] * st->nspc; |
0839bdeb | 92 | io->i_flgs &= ~F_TYPEMASK; |
258a5c40 SL |
93 | } |
94 | ||
95 | upstrategy(io, func) | |
96 | register struct iob *io; | |
97 | { | |
1f4919da | 98 | int cn, tn, sn, o; |
b8ca3ab9 | 99 | register unit = io->i_unit; |
258a5c40 SL |
100 | daddr_t bn; |
101 | int recal, info, waitdry; | |
102 | register struct updevice *upaddr = | |
b8ca3ab9 HS |
103 | (struct updevice *)ubamem(unit, ubastd[0]); |
104 | register struct st *st = &upst[up_type[unit]]; | |
1f4919da | 105 | int doprintf = 0; |
258a5c40 | 106 | |
b8ca3ab9 | 107 | sectsiz = SECTSIZ; |
3ab40097 | 108 | if (io->i_flgs & (F_HDR|F_HCHECK)) |
b8ca3ab9 | 109 | sectsiz += HDRSIZ; |
dda2842d | 110 | upaddr->upcs2 = unit % 8; |
258a5c40 SL |
111 | if ((upaddr->upds & UPDS_VV) == 0) { |
112 | upaddr->upcs1 = UP_DCLR|UP_GO; | |
113 | upaddr->upcs1 = UP_PRESET|UP_GO; | |
114 | upaddr->upof = UPOF_FMT22; | |
115 | } | |
3ab40097 | 116 | if ((upaddr->upds & UPDS_DREADY) == 0) |
258a5c40 SL |
117 | _stop("up not ready"); |
118 | info = ubasetup(io, 1); | |
119 | upaddr->upwc = -io->i_cc / sizeof (short); | |
3ab40097 SL |
120 | recal = 0; |
121 | io->i_errcnt = 0; | |
122 | ||
960ade39 | 123 | restart: |
1f4919da SL |
124 | o = io->i_cc + (upaddr->upwc * sizeof (short)); |
125 | upaddr->upba = info + o; | |
126 | bn = io->i_bn + o / sectsiz; | |
f1a67d74 | 127 | if (doprintf && updebug[unit] & (UPF_ECCDEBUG|UPF_BSEDEBUG)) |
3beb607b | 128 | printf("wc=%d o=%d i_bn=%d bn=%d\n", |
dda2842d | 129 | upaddr->upwc, o, io->i_bn, bn); |
0839bdeb SL |
130 | while((upaddr->upds & UPDS_DRY) == 0) |
131 | ; | |
b8ca3ab9 HS |
132 | if (upstart(io, bn) != 0) { |
133 | ubafree(io, info); | |
258a5c40 | 134 | return (-1); |
b8ca3ab9 | 135 | } |
258a5c40 SL |
136 | do { |
137 | DELAY(25); | |
138 | } while ((upaddr->upcs1 & UP_RDY) == 0); | |
3ab40097 SL |
139 | /* |
140 | * If transfer has completed, free UNIBUS | |
141 | * resources and return transfer size. | |
142 | */ | |
143 | if ((upaddr->upds&UPDS_ERR) == 0 && (upaddr->upcs1&UP_TRE) == 0) { | |
b8ca3ab9 | 144 | ubafree(io, info); |
3ab40097 | 145 | return (io->i_cc); |
b8ca3ab9 | 146 | } |
dda2842d SL |
147 | if (updebug[unit] & (UPF_ECCDEBUG|UPF_BSEDEBUG)) { |
148 | printf("up error: (cyl,trk,sec)=(%d,%d,%d) ", | |
3beb607b SL |
149 | upaddr->updc, upaddr->upda>>8, (upaddr->upda&0x1f)-1); |
150 | printf("cs2=%b er1=%b er2=%b wc=%d\n", | |
dda2842d | 151 | upaddr->upcs2, UPCS2_BITS, upaddr->uper1, |
3beb607b | 152 | UPER1_BITS, upaddr->uper2, UPER2_BITS, upaddr->upwc); |
dda2842d | 153 | } |
258a5c40 | 154 | waitdry = 0; |
3beb607b | 155 | while ((upaddr->upds&UPDS_DRY) == 0 && ++waitdry < sectsiz) |
0839bdeb | 156 | DELAY(5); |
3ab40097 SL |
157 | if (upaddr->uper1&UPER1_WLE) { |
158 | /* | |
159 | * Give up on write locked devices immediately. | |
160 | */ | |
161 | printf("up%d: write locked\n", unit); | |
162 | return (-1); | |
163 | } | |
258a5c40 SL |
164 | if (++io->i_errcnt > 27) { |
165 | /* | |
166 | * After 28 retries (16 without offset, and | |
167 | * 12 with offset positioning) give up. | |
1f4919da SL |
168 | * But first, if the error is a header CRC, |
169 | * check if a replacement sector exists in | |
170 | * the bad sector table. | |
258a5c40 | 171 | */ |
1f4919da SL |
172 | if ((upaddr->uper1&UPER1_HCRC) && (io->i_flgs&F_NBSF) == 0 && |
173 | upecc(io, BSE) == 0) | |
174 | goto success; | |
0839bdeb | 175 | io->i_error = EHER; |
0839bdeb SL |
176 | if (upaddr->upcs2 & UPCS2_WCE) |
177 | io->i_error = EWCK; | |
b8ca3ab9 | 178 | hard: |
3ab40097 SL |
179 | bn = io->i_bn + |
180 | (io->i_cc + upaddr->upwc * sizeof (short)) / sectsiz; | |
258a5c40 SL |
181 | cn = bn/st->nspc; |
182 | sn = bn%st->nspc; | |
183 | tn = sn/st->nsect; | |
184 | sn = sn%st->nsect; | |
3ab40097 SL |
185 | printf( |
186 | "up error: (cyl,trk,sec)=(%d,%d,%d) cs2=%b er1=%b er2=%b\n", | |
187 | cn, tn, sn, | |
188 | upaddr->upcs2, UPCS2_BITS, upaddr->uper1, | |
189 | UPER1_BITS, upaddr->uper2, UPER2_BITS); | |
258a5c40 | 190 | upaddr->upcs1 = UP_TRE|UP_DCLR|UP_GO; |
b8ca3ab9 | 191 | io->i_errblk = bn; |
3ab40097 SL |
192 | return (io->i_cc + upaddr->upwc * sizeof(short)); |
193 | } | |
194 | if (upaddr->uper2 & UPER2_BSE) { | |
b4736392 | 195 | if ((io->i_flgs&F_NBSF) == 0 && upecc(io, BSE) == 0) |
258a5c40 | 196 | goto success; |
3ab40097 SL |
197 | io->i_error = EBSE; |
198 | goto hard; | |
258a5c40 | 199 | } |
3ab40097 | 200 | /* |
3beb607b SL |
201 | * ECC error. If a soft error, correct it; |
202 | * otherwise fall through and retry the transfer. | |
3ab40097 | 203 | */ |
3beb607b SL |
204 | if ((upaddr->uper1 & (UPER1_DCK|UPER1_ECH)) == UPER1_DCK) { |
205 | if (upecc(io, ECC) == 0) | |
206 | goto success; | |
207 | io->i_error = EECC; | |
208 | goto hard; | |
3ab40097 | 209 | } |
258a5c40 SL |
210 | /* |
211 | * Clear drive error and, every eight attempts, | |
212 | * (starting with the fourth) | |
213 | * recalibrate to clear the slate. | |
214 | */ | |
215 | upaddr->upcs1 = UP_TRE|UP_DCLR|UP_GO; | |
960ade39 | 216 | if ((io->i_errcnt&07) == 4 ) { |
258a5c40 | 217 | upaddr->upcs1 = UP_RECAL|UP_GO; |
960ade39 HS |
218 | recal = 1; |
219 | goto restart; | |
258a5c40 SL |
220 | } |
221 | /* | |
222 | * Advance recalibration finite state machine | |
223 | * if recalibrate in progress, through | |
224 | * RECAL | |
225 | * SEEK | |
226 | * OFFSET (optional) | |
227 | * RETRY | |
228 | */ | |
229 | switch (recal) { | |
230 | ||
231 | case 1: | |
232 | upaddr->updc = cn; | |
233 | upaddr->upcs1 = UP_SEEK|UP_GO; | |
3ab40097 | 234 | recal = 2; |
960ade39 | 235 | goto restart; |
0839bdeb | 236 | |
258a5c40 SL |
237 | case 2: |
238 | if (io->i_errcnt < 16 || (func & READ) == 0) | |
239 | goto donerecal; | |
240 | upaddr->upof = up_offset[io->i_errcnt & 017] | UPOF_FMT22; | |
241 | upaddr->upcs1 = UP_OFFSET|UP_GO; | |
3ab40097 | 242 | recal = 3; |
960ade39 | 243 | goto restart; |
0839bdeb | 244 | |
258a5c40 SL |
245 | donerecal: |
246 | case 3: | |
247 | recal = 0; | |
258a5c40 SL |
248 | break; |
249 | } | |
250 | /* | |
960ade39 HS |
251 | * If we were offset positioning, |
252 | * return to centerline. | |
258a5c40 | 253 | */ |
960ade39 HS |
254 | if (io->i_errcnt >= 16) { |
255 | upaddr->upof = UPOF_FMT22; | |
256 | upaddr->upcs1 = UP_RTC|UP_GO; | |
257 | while ((upaddr->upds&UPDS_DRY) == 0) | |
258 | DELAY(25); | |
258a5c40 | 259 | } |
960ade39 | 260 | goto restart; |
3ab40097 | 261 | |
258a5c40 | 262 | success: |
3beb607b SL |
263 | #define rounddown(x, y) (((x) / (y)) * (y)) |
264 | upaddr->upwc = rounddown(upaddr->upwc, sectsiz / sizeof (short)); | |
265 | if (upaddr->upwc) { | |
1f4919da | 266 | doprintf++; |
960ade39 | 267 | goto restart; |
1f4919da | 268 | } |
258a5c40 | 269 | /* |
dda2842d | 270 | * Release UNIBUS |
258a5c40 SL |
271 | */ |
272 | ubafree(io, info); | |
273 | return (io->i_cc); | |
274 | } | |
275 | ||
276 | /* | |
b4736392 SL |
277 | * Correct an ECC error, and restart the |
278 | * i/o to complete the transfer (if necessary). | |
279 | * This is quite complicated because the transfer | |
280 | * may be going to an odd memory address base and/or | |
258a5c40 SL |
281 | * across a page boundary. |
282 | */ | |
0839bdeb | 283 | upecc(io, flag) |
258a5c40 SL |
284 | register struct iob *io; |
285 | int flag; | |
286 | { | |
dda2842d | 287 | register i, unit = io->i_unit; |
258a5c40 | 288 | register struct updevice *up = |
dda2842d | 289 | (struct updevice *)ubamem(unit, ubastd[0]); |
b8ca3ab9 | 290 | register struct st *st; |
258a5c40 | 291 | caddr_t addr; |
6796f4df | 292 | int bn, twc, npf, mask, cn, tn, sn; |
b8ca3ab9 | 293 | daddr_t bbn; |
258a5c40 SL |
294 | |
295 | /* | |
b4736392 SL |
296 | * Npf is the number of sectors transferred |
297 | * before the sector containing the ECC error; | |
298 | * bn is the current block number. | |
258a5c40 | 299 | */ |
b8ca3ab9 | 300 | twc = up->upwc; |
b4736392 | 301 | npf = ((twc * sizeof(short)) + io->i_cc) / sectsiz; |
dda2842d | 302 | if (updebug[unit] & UPF_ECCDEBUG) |
3beb607b SL |
303 | printf("npf=%d mask=0x%x ec1=%d wc=%d\n", |
304 | npf, up->upec2, up->upec1, twc); | |
1f4919da | 305 | bn = io->i_bn + npf; |
dda2842d | 306 | st = &upst[up_type[unit]]; |
6796f4df HS |
307 | cn = bn/st->nspc; |
308 | sn = bn%st->nspc; | |
309 | tn = sn/st->nsect; | |
310 | sn = sn%st->nsect; | |
b4736392 | 311 | |
258a5c40 | 312 | /* |
b4736392 | 313 | * ECC correction. |
258a5c40 SL |
314 | */ |
315 | if (flag == ECC) { | |
1f4919da | 316 | int bit, o, ecccnt; |
3ab40097 | 317 | |
b8ca3ab9 | 318 | ecccnt = 0; |
258a5c40 | 319 | mask = up->upec2; |
dda2842d | 320 | printf("up%d: soft ecc sn%d\n", unit, bn); |
258a5c40 | 321 | /* |
1f4919da SL |
322 | * Compute the byte and bit position of |
323 | * the error. o is the byte offset in | |
324 | * the transfer at which the correction | |
325 | * applied. | |
258a5c40 | 326 | */ |
1f4919da | 327 | npf--; |
258a5c40 | 328 | i = up->upec1 - 1; /* -1 makes 0 origin */ |
3beb607b SL |
329 | bit = i & 07; |
330 | o = (i & ~07) >> 3; | |
258a5c40 SL |
331 | up->upcs1 = UP_TRE|UP_DCLR|UP_GO; |
332 | /* | |
b4736392 SL |
333 | * Correct while possible bits remain of mask. |
334 | * Since mask contains 11 bits, we continue while | |
335 | * the bit offset is > -11. Also watch out for | |
336 | * end of this block and the end of the transfer. | |
258a5c40 | 337 | */ |
1f4919da | 338 | while (o < sectsiz && (npf*sectsiz)+o < io->i_cc && bit > -11) { |
258a5c40 | 339 | /* |
b4736392 | 340 | * addr = |
1f4919da | 341 | * (base address of transfer) + |
b4736392 SL |
342 | * (# sectors transferred before the error) * |
343 | * (sector size) + | |
1f4919da | 344 | * (byte offset to incorrect data) |
258a5c40 | 345 | */ |
1f4919da | 346 | addr = io->i_ma + (npf * sectsiz) + o; |
1f4919da SL |
347 | /* |
348 | * No data transfer occurs with a write check, | |
349 | * so don't correct the resident copy of data. | |
350 | */ | |
dda2842d SL |
351 | if ((io->i_flgs & (F_CHECK|F_HCHECK)) == 0) { |
352 | if (updebug[unit] & UPF_ECCDEBUG) | |
353 | printf("addr=0x%x old=0x%x ", addr, | |
354 | (*addr&0xff)); | |
b8ca3ab9 | 355 | *addr ^= (mask << bit); |
dda2842d SL |
356 | if (updebug[unit] & UPF_ECCDEBUG) |
357 | printf("new=0x%x\n", (*addr&0xff)); | |
358 | } | |
1f4919da | 359 | o++, bit -= 8; |
3ab40097 SL |
360 | if ((io->i_flgs&F_ECCLM) && ++ecccnt > MAXECC) |
361 | return (1); | |
258a5c40 | 362 | } |
3ab40097 SL |
363 | return (0); |
364 | } | |
b4736392 SL |
365 | |
366 | /* | |
367 | * Bad sector forwarding. | |
368 | */ | |
3ab40097 | 369 | if (flag == BSE) { |
258a5c40 | 370 | /* |
b4736392 SL |
371 | * If not in bad sector table, |
372 | * indicate a hard error to caller. | |
258a5c40 | 373 | */ |
258a5c40 | 374 | up->upcs1 = UP_TRE|UP_DCLR|UP_GO; |
dda2842d | 375 | if ((bbn = isbad(&upbad[unit], cn, tn, sn)) < 0) |
3ab40097 | 376 | return (1); |
3beb607b | 377 | bbn = (st->ncyl * st->nspc) - st->nsect - 1 - bbn; |
b8ca3ab9 | 378 | twc = up->upwc + sectsiz; |
3ab40097 | 379 | up->upwc = - (sectsiz / sizeof (short)); |
dda2842d SL |
380 | if (updebug[unit] & UPF_BSEDEBUG) |
381 | printf("revector sn %d to %d\n", sn, bbn); | |
258a5c40 | 382 | /* |
b4736392 SL |
383 | * Clear the drive & read the replacement |
384 | * sector. If this is in the middle of a | |
385 | * transfer, then set up the controller | |
386 | * registers in a normal fashion. | |
387 | * The UNIBUS address need not be changed. | |
388 | */ | |
3beb607b | 389 | while ((up->upcs1 & UP_RDY) == 0) |
258a5c40 | 390 | ; |
3beb607b | 391 | if (upstart(io, bbn)) |
b8ca3ab9 HS |
392 | return (1); /* error */ |
393 | io->i_errcnt = 0; /* success */ | |
258a5c40 SL |
394 | do { |
395 | DELAY(25); | |
3beb607b SL |
396 | } while ((up->upcs1 & UP_RDY) == 0) ; |
397 | if ((up->upds & UPDS_ERR) || (up->upcs1 & UP_TRE)) { | |
398 | up->upwc = twc - sectsiz; | |
b8ca3ab9 | 399 | return (1); |
258a5c40 SL |
400 | } |
401 | } | |
960ade39 | 402 | if (twc) |
258a5c40 | 403 | up->upwc = twc; |
b8ca3ab9 | 404 | return (0); |
258a5c40 | 405 | } |
258a5c40 SL |
406 | |
407 | upstart(io, bn) | |
0839bdeb SL |
408 | register struct iob *io; |
409 | daddr_t bn; | |
258a5c40 SL |
410 | { |
411 | register struct updevice *upaddr = | |
0839bdeb | 412 | (struct updevice *)ubamem(io->i_unit, ubastd[0]); |
b8ca3ab9 | 413 | register struct st *st = &upst[up_type[io->i_unit]]; |
258a5c40 SL |
414 | int sn, tn; |
415 | ||
416 | sn = bn%st->nspc; | |
417 | tn = sn/st->nsect; | |
418 | sn %= st->nsect; | |
419 | upaddr->updc = bn/st->nspc; | |
420 | upaddr->upda = (tn << 8) + sn; | |
b8ca3ab9 | 421 | switch (io->i_flgs & F_TYPEMASK) { |
0839bdeb SL |
422 | |
423 | case F_RDDATA: | |
424 | upaddr->upcs1 = UP_RCOM|UP_GO; | |
425 | break; | |
426 | ||
427 | case F_WRDATA: | |
428 | upaddr->upcs1 = UP_WCOM|UP_GO; | |
258a5c40 | 429 | break; |
0839bdeb SL |
430 | |
431 | case F_HDR|F_RDDATA: | |
432 | upaddr->upcs1 = UP_RHDR|UP_GO; | |
433 | break; | |
434 | ||
435 | case F_HDR|F_WRDATA: | |
436 | upaddr->upcs1 = UP_WHDR|UP_GO; | |
258a5c40 | 437 | break; |
0839bdeb SL |
438 | |
439 | case F_CHECK|F_WRDATA: | |
440 | case F_CHECK|F_RDDATA: | |
258a5c40 SL |
441 | upaddr->upcs1 = UP_WCDATA|UP_GO; |
442 | break; | |
0839bdeb SL |
443 | |
444 | case F_HCHECK|F_WRDATA: | |
445 | case F_HCHECK|F_RDDATA: | |
258a5c40 SL |
446 | upaddr->upcs1 = UP_WCHDR|UP_GO; |
447 | break; | |
0839bdeb | 448 | |
258a5c40 | 449 | default: |
0839bdeb SL |
450 | io->i_error = ECMD; |
451 | io->i_flgs &= ~F_TYPEMASK; | |
452 | return (1); | |
258a5c40 | 453 | } |
0839bdeb | 454 | return (0); |
258a5c40 SL |
455 | } |
456 | ||
0839bdeb SL |
457 | /*ARGSUSED*/ |
458 | upioctl(io, cmd, arg) | |
459 | struct iob *io; | |
460 | int cmd; | |
461 | caddr_t arg; | |
462 | { | |
dda2842d SL |
463 | int unit = io->i_unit, flag; |
464 | struct st *st = &upst[up_type[unit]], *tmp; | |
b8ca3ab9 HS |
465 | |
466 | switch(cmd) { | |
467 | ||
dda2842d SL |
468 | case SAIODEBUG: |
469 | flag = (int)arg; | |
470 | if (flag > 0) | |
471 | updebug[unit] |= flag; | |
472 | else | |
473 | updebug[unit] &= ~flag; | |
474 | return (0); | |
475 | ||
b8ca3ab9 HS |
476 | case SAIODEVDATA: |
477 | tmp = (struct st *)arg; | |
478 | *tmp = *st; | |
3ab40097 | 479 | return (0); |
b8ca3ab9 | 480 | } |
3ab40097 | 481 | return (ECMD); |
b8ca3ab9 | 482 | } |