Commit | Line | Data |
---|---|---|
15637ed4 | 1 | /* |
a0becc21 | 2 | * Written by Julian Elischer (julian@tfs.com)(now julian@DIALix.oz.au) |
15637ed4 RG |
3 | * for TRW Financial Systems for use under the MACH(2.5) operating system. |
4 | * | |
5 | * TRW Financial Systems, in accordance with their agreement with Carnegie | |
6 | * Mellon University, makes this software available to CMU to distribute | |
7 | * or use in any manner that they see fit as long as this message is kept with | |
8 | * the software. For this reason TFS also grants any other persons or | |
9 | * organisations permission to use or modify this software. | |
10 | * | |
11 | * TFS supplies this software to be publicly redistributed | |
12 | * on the understanding that TFS is not responsible for the correct | |
13 | * functioning of this software in any circumstances. | |
14 | * | |
519fb2b7 RG |
15 | * |
16 | * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE | |
17 | * -------------------- ----- ---------------------- | |
18 | * CURRENT PATCH LEVEL: 1 00098 | |
19 | * -------------------- ----- ---------------------- | |
20 | * | |
21 | * 16 Feb 93 Julian Elischer ADDED for SCSI system | |
22 | * 1.15 is the last version to support MACH and OSF/1 | |
23 | */ | |
8387479d | 24 | /* $Revision: 1.15 $ */ |
519fb2b7 RG |
25 | |
26 | /* | |
15637ed4 | 27 | * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 |
a0becc21 | 28 | * major changes by Julian Elischer (julian@jules.dialix.oz.au) May 1993 |
98639498 | 29 | * |
8387479d | 30 | * $Id: st.c,v 1.15 1994/01/29 10:30:41 rgrimes Exp $ |
15637ed4 RG |
31 | */ |
32 | ||
15637ed4 RG |
33 | /* |
34 | * To do: | |
35 | * work out some better way of guessing what a good timeout is going | |
36 | * to be depending on whether we expect to retension or not. | |
37 | * | |
38 | */ | |
39 | ||
40 | #include <sys/types.h> | |
41 | #include <st.h> | |
42 | ||
43 | #include <sys/param.h> | |
44 | #include <sys/systm.h> | |
45 | ||
fca1f689 | 46 | #include <fcntl.h> |
15637ed4 RG |
47 | #include <sys/errno.h> |
48 | #include <sys/ioctl.h> | |
d4284689 | 49 | #include <sys/malloc.h> |
15637ed4 RG |
50 | #include <sys/buf.h> |
51 | #include <sys/proc.h> | |
52 | #include <sys/user.h> | |
53 | #include <sys/mtio.h> | |
54 | ||
15637ed4 RG |
55 | #include <scsi/scsi_all.h> |
56 | #include <scsi/scsi_tape.h> | |
57 | #include <scsi/scsiconf.h> | |
58 | ||
519fb2b7 | 59 | u_int32 ststrats, stqueues; |
15637ed4 | 60 | |
a0becc21 NW |
61 | /* Defines for device specific stuff */ |
62 | #define PAGE_0_SENSE_DATA_SIZE 12 | |
15637ed4 | 63 | #define PAGESIZ 4096 |
a0becc21 | 64 | #define DEF_FIXED_BSIZE 512 |
519fb2b7 | 65 | #define ST_RETRIES 4 /* only on non IO commands */ |
15637ed4 RG |
66 | |
67 | #define MODE(z) ( (minor(z) & 0x03) ) | |
68 | #define DSTY(z) ( ((minor(z) >> 2) & 0x03) ) | |
69 | #define UNIT(z) ( (minor(z) >> 4) ) | |
519fb2b7 | 70 | #define CTLMODE 3 |
15637ed4 | 71 | |
a0becc21 | 72 | #define SCSI_2_MAX_DENSITY_CODE 0x17 /* maximum density code specified |
519fb2b7 RG |
73 | * in SCSI II spec. */ |
74 | /* | |
75 | * Define various devices that we know mis-behave in some way, | |
76 | * and note how they are bad, so we can correct for them | |
77 | */ | |
78 | struct modes { | |
79 | u_int32 blksiz; | |
80 | u_int32 quirks; /* same definitions as in rogues */ | |
81 | char density; | |
82 | char spare[3]; | |
a0becc21 | 83 | }; |
519fb2b7 RG |
84 | |
85 | struct rogues { | |
86 | char *name; | |
87 | char *manu; | |
88 | char *model; | |
89 | char *version; | |
90 | u_int32 quirks; /* valid for all modes */ | |
91 | struct modes modes[4]; | |
a0becc21 NW |
92 | }; |
93 | ||
94 | /* define behaviour codes (quirks) */ | |
95 | #define ST_Q_NEEDS_PAGE_0 0x00001 | |
96 | #define ST_Q_FORCE_FIXED_MODE 0x00002 | |
97 | #define ST_Q_FORCE_VAR_MODE 0x00004 | |
519fb2b7 | 98 | #define ST_Q_SNS_HLP 0x00008 /* must do READ for good MODE SENSE */ |
0269d546 | 99 | #define ST_Q_IGNORE_LOADS 0x00010 |
519fb2b7 | 100 | #define ST_Q_BLKSIZ 0x00020 /* variable-block media_blksiz > 0 */ |
a0becc21 | 101 | |
519fb2b7 | 102 | static struct rogues gallery[] = /* ends with an all-null entry */ |
a0becc21 | 103 | { |
519fb2b7 RG |
104 | {"Such an old device ", "pre-scsi", " unknown model ", "????", |
105 | 0, | |
106 | { | |
107 | {512, ST_Q_FORCE_FIXED_MODE, 0}, /* minor 0,1,2,3 */ | |
108 | {512, ST_Q_FORCE_FIXED_MODE, QIC_24}, /* minor 4,5,6,7 */ | |
109 | {0, ST_Q_FORCE_VAR_MODE, HALFINCH_1600}, /* minor 8,9,10,11 */ | |
110 | {0, ST_Q_FORCE_VAR_MODE, HALFINCH_6250} /* minor 12,13,14,15 */ | |
111 | } | |
112 | }, | |
113 | {"Tandberg tdc3600", "TANDBERG", " TDC 3600", "????", | |
114 | ST_Q_NEEDS_PAGE_0, | |
115 | { | |
116 | {0, 0, 0}, /* minor 0,1,2,3 */ | |
117 | {0, ST_Q_FORCE_VAR_MODE, QIC_525}, /* minor 4,5,6,7 */ | |
118 | {0, 0, QIC_150}, /* minor 8,9,10,11 */ | |
119 | {0, 0, QIC_120} /* minor 12,13,14,15 */ | |
120 | } | |
121 | }, | |
122 | {"Rev 5 of the Archive 2525", "ARCHIVE ", "VIPER 2525 25462", "-005", | |
123 | 0, | |
124 | { | |
125 | {0, ST_Q_SNS_HLP, 0}, /* minor 0,1,2,3 */ | |
126 | {0, ST_Q_SNS_HLP, QIC_525}, /* minor 4,5,6,7 */ | |
127 | {0, 0, QIC_150}, /* minor 8,9,10,11 */ | |
128 | {0, 0, QIC_120} /* minor 12,13,14,15 */ | |
129 | } | |
130 | }, | |
131 | {"Archive Viper 150", "ARCHIVE ", "VIPER 150", "????", | |
132 | ST_Q_NEEDS_PAGE_0, | |
133 | { | |
134 | {0, 0, 0}, /* minor 0,1,2,3 */ | |
135 | {0, 0, QIC_150}, /* minor 4,5,6,7 */ | |
136 | {0, 0, QIC_120}, /* minor 8,9,10,11 */ | |
137 | {0, 0, QIC_24} /* minor 12,13,14,15 */ | |
138 | } | |
139 | }, | |
140 | {"Wangtek 5525ES", "WANGTEK ", "5525ES SCSI REV7", "????", | |
141 | 0, | |
142 | { | |
143 | {0, 0, 0}, /* minor 0,1,2,3 */ | |
144 | {0, ST_Q_BLKSIZ, QIC_525}, /* minor 4,5,6,7 */ | |
145 | {0, 0, QIC_150}, /* minor 8,9,10,11 */ | |
146 | {0, 0, QIC_120} /* minor 12,13,14,15 */ | |
147 | } | |
148 | }, | |
149 | {"WangDAT model 1300", "WangDAT ", "Model 1300", "????", | |
150 | 0, | |
151 | { | |
152 | {0, 0, 0}, /* minor 0,1,2,3 */ | |
153 | {512, ST_Q_FORCE_FIXED_MODE, 0x13}, /* minor 4,5,6,7 */ | |
154 | {1024, ST_Q_FORCE_FIXED_MODE, 0x13}, /* minor 8,9,10,11 */ | |
155 | {0, ST_Q_FORCE_VAR_MODE, 0x13} /* minor 12,13,14,15 */ | |
156 | } | |
157 | }, | |
158 | {(char *) 0} | |
a0becc21 | 159 | }; |
15637ed4 | 160 | |
519fb2b7 RG |
161 | errval st_space __P((u_int32 unit, int32 number, u_int32 what, u_int32 flags)); |
162 | errval st_rewind __P((u_int32 unit, boolean immed, u_int32 flags)); | |
163 | errval st_mode_sense __P((u_int32 unit, u_int32 flags)); | |
164 | errval st_decide_mode __P((u_int32 unit, boolean first_read)); | |
165 | errval st_rd_blk_lim __P((u_int32 unit, u_int32 flags)); | |
166 | errval st_touch_tape __P((u_int32 unit)); | |
167 | errval st_write_filemarks __P((u_int32 unit, int32 number, u_int32 flags)); | |
168 | errval st_load __P((u_int32 unit, u_int32 type, u_int32 flags)); | |
169 | errval st_mode_select __P((u_int32 unit, u_int32 flags)); | |
170 | void ststrategy(); | |
171 | void stminphys(); | |
172 | int32 st_chkeod(); | |
173 | errval stattach(); | |
174 | void ststart(); | |
175 | void st_unmount(); | |
176 | errval st_mount_tape(); | |
177 | void st_loadquirks(); | |
178 | void st_identify_drive(); | |
179 | errval st_interpret_sense(); | |
15637ed4 | 180 | |
15637ed4 | 181 | #define ESUCCESS 0 |
519fb2b7 RG |
182 | #define NOEJECT 0 |
183 | #define EJECT 1 | |
15637ed4 | 184 | |
519fb2b7 | 185 | struct scsi_device st_switch = |
15637ed4 | 186 | { |
519fb2b7 RG |
187 | st_interpret_sense, /* check errors with us first */ |
188 | ststart, /* we have a queue, and this is how we service it */ | |
189 | NULL, | |
190 | NULL, /* use the default 'done' routine */ | |
191 | "st", | |
192 | 0, | |
193 | { 0, 0 } | |
194 | }; | |
195 | ||
196 | struct st_data { | |
a0becc21 | 197 | /*--------------------present operating parameters, flags etc.----------------*/ |
519fb2b7 RG |
198 | u_int32 flags; /* see below */ |
199 | u_int32 blksiz; /* blksiz we are using */ | |
200 | u_int32 density; /* present density */ | |
201 | u_int32 quirks; /* quirks for the open mode */ | |
202 | u_int32 last_dsty; /* last density openned */ | |
a0becc21 | 203 | /*--------------------device/scsi parameters----------------------------------*/ |
519fb2b7 | 204 | struct scsi_link *sc_link; /* our link to the adpter etc. */ |
a0becc21 | 205 | /*--------------------parameters reported by the device ----------------------*/ |
519fb2b7 RG |
206 | u_int32 blkmin; /* min blk size */ |
207 | u_int32 blkmax; /* max blk size */ | |
208 | struct rogues *rogues; /* if we have a rogue entry */ | |
a0becc21 | 209 | /*--------------------parameters reported by the device for this media--------*/ |
519fb2b7 RG |
210 | u_int32 numblks; /* nominal blocks capacity */ |
211 | u_int32 media_blksiz; /* 0 if not ST_FIXEDBLOCKS */ | |
212 | u_int32 media_density; /* this is what it said when asked */ | |
a0becc21 | 213 | /*--------------------quirks for the whole drive------------------------------*/ |
519fb2b7 | 214 | u_int32 drive_quirks; /* quirks of this drive */ |
a0becc21 | 215 | /*--------------------How we should set up when openning each minor device----*/ |
519fb2b7 RG |
216 | struct modes modes[4]; /* plus more for each mode */ |
217 | u_int8 modeflags[4]; /* flags for the modes */ | |
218 | #define DENSITY_SET_BY_USER 0x01 | |
219 | #define DENSITY_SET_BY_QUIRK 0x02 | |
220 | #define BLKSIZE_SET_BY_USER 0x04 | |
221 | #define BLKSIZE_SET_BY_QUIRK 0x08 | |
a0becc21 | 222 | /*--------------------storage for sense data returned by the drive------------*/ |
519fb2b7 RG |
223 | unsigned char sense_data[12]; /* |
224 | * additional sense data needed | |
225 | * for mode sense/select. | |
226 | */ | |
227 | struct buf *buf_queue; /* the queue of pending IO operations */ | |
228 | struct scsi_xfer scsi_xfer; /* scsi xfer struct for this drive */ | |
229 | u_int32 xfer_block_wait; /* is a process waiting? */ | |
230 | } *st_data[NST]; | |
231 | ||
a0becc21 NW |
232 | #define ST_INITIALIZED 0x01 |
233 | #define ST_INFO_VALID 0x02 | |
234 | #define ST_OPEN 0x04 | |
519fb2b7 RG |
235 | #define ST_BLOCK_SET 0x08 /* block size, mode set by ioctl */ |
236 | #define ST_WRITTEN 0x10 /* data have been written, EOD needed */ | |
a0becc21 NW |
237 | #define ST_FIXEDBLOCKS 0x20 |
238 | #define ST_AT_FILEMARK 0x40 | |
519fb2b7 RG |
239 | #define ST_EIO_PENDING 0x80 /* we couldn't report it then (had data) */ |
240 | #define ST_NEW_MOUNT 0x100 /* still need to decide mode */ | |
241 | #define ST_READONLY 0x200 /* st_mode_sense says write protected */ | |
242 | #define ST_FM_WRITTEN 0x400 /* | |
243 | * EOF file mark written -- used with | |
244 | * ~ST_WRITTEN to indicate that multiple file | |
245 | * marks have been written | |
246 | */ | |
247 | #define ST_BLANK_READ 0x800 /* BLANK CHECK encountered already */ | |
248 | #define ST_2FM_AT_EOD 0x1000 /* write 2 file marks at EOD */ | |
249 | #define ST_MOUNTED 0x2000 /* Device is presently mounted */ | |
fca1f689 RG |
250 | |
251 | #define ST_PER_ACTION (ST_AT_FILEMARK | ST_EIO_PENDING | ST_BLANK_READ) | |
519fb2b7 RG |
252 | #define ST_PER_MOUNT (ST_INFO_VALID | ST_BLOCK_SET | ST_WRITTEN | \ |
253 | ST_FIXEDBLOCKS | ST_READONLY | \ | |
fca1f689 | 254 | ST_FM_WRITTEN | ST_2FM_AT_EOD | ST_PER_ACTION) |
15637ed4 | 255 | |
519fb2b7 | 256 | static u_int32 next_st_unit = 0; |
15637ed4 | 257 | |
519fb2b7 RG |
258 | /* |
259 | * The routine called by the low level scsi routine when it discovers | |
260 | * A device suitable for this driver | |
261 | */ | |
262 | ||
263 | errval | |
264 | stattach(sc_link) | |
265 | struct scsi_link *sc_link; | |
15637ed4 | 266 | { |
519fb2b7 | 267 | u_int32 unit; |
15637ed4 RG |
268 | struct st_data *st; |
269 | ||
519fb2b7 RG |
270 | SC_DEBUG(sc_link, SDEV_DB2, ("stattach: ")); |
271 | /* | |
272 | * Check we have the resources for another drive | |
273 | */ | |
15637ed4 | 274 | unit = next_st_unit++; |
519fb2b7 RG |
275 | |
276 | if (unit >= NST) { | |
869c4419 | 277 | printf("Too many scsi tapes..(%d > %d) reconfigure kernel\n", |
519fb2b7 RG |
278 | (unit + 1), NST); |
279 | return 0; | |
15637ed4 | 280 | } |
519fb2b7 RG |
281 | if (st_data[unit]) { |
282 | printf("st%d: Already has storage!\n", unit); | |
283 | return 0; | |
d4284689 | 284 | } |
519fb2b7 RG |
285 | sc_link->device = &st_switch; |
286 | sc_link->dev_unit = unit; | |
287 | st = st_data[unit] = malloc(sizeof(struct st_data), M_DEVBUF, M_NOWAIT); | |
288 | if (!st) { | |
289 | printf("st%d: malloc failed in st.c\n", unit); | |
290 | return 0; | |
d4284689 | 291 | } |
519fb2b7 RG |
292 | bzero(st, sizeof(struct st_data)); |
293 | ||
294 | /* | |
295 | * Store information needed to contact our base driver | |
296 | */ | |
297 | st->sc_link = sc_link; | |
298 | ||
299 | /* | |
300 | * Check if the drive is a known criminal and take | |
301 | * Any steps needed to bring it into line | |
302 | */ | |
a0becc21 | 303 | st_identify_drive(unit); |
15637ed4 | 304 | |
519fb2b7 RG |
305 | /* |
306 | * Use the subdriver to request information regarding | |
307 | * the drive. We cannot use interrupts yet, so the | |
308 | * request must specify this. | |
309 | */ | |
310 | if (st_mode_sense(unit, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT)) { | |
d4284689 | 311 | printf("st%d: drive offline\n", unit); |
519fb2b7 RG |
312 | } else { |
313 | printf("st%d: density code 0x%x, ", unit, st->media_density); | |
314 | if (!scsi_test_unit_ready(sc_link, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT)) { | |
315 | if (st->media_blksiz) { | |
d4284689 | 316 | printf("%d-byte", st->media_blksiz); |
519fb2b7 | 317 | } else { |
d4284689 RG |
318 | printf("variable"); |
319 | } | |
320 | printf(" blocks, write-%s\n", | |
519fb2b7 RG |
321 | (st->flags & ST_READONLY) ? "protected" : "enabled"); |
322 | } else { | |
323 | printf(" drive empty\n"); | |
a0becc21 | 324 | } |
15637ed4 | 325 | } |
519fb2b7 RG |
326 | /* |
327 | * Set up the buf queue for this device | |
328 | */ | |
329 | st->buf_queue = 0; | |
a0becc21 | 330 | st->flags |= ST_INITIALIZED; |
519fb2b7 | 331 | return 0; |
15637ed4 RG |
332 | } |
333 | ||
519fb2b7 RG |
334 | /* |
335 | * Use the inquiry routine in 'scsi_base' to get drive info so we can | |
336 | * Further tailor our behaviour. | |
337 | */ | |
338 | void | |
a0becc21 | 339 | st_identify_drive(unit) |
519fb2b7 | 340 | u_int32 unit; |
a0becc21 | 341 | { |
519fb2b7 RG |
342 | struct st_data *st = st_data[unit]; |
343 | struct scsi_inquiry_data inqbuf; | |
344 | struct rogues *finger; | |
345 | char manu[32]; | |
346 | char model[32]; | |
347 | char model2[32]; | |
348 | char version[32]; | |
349 | u_int32 model_len; | |
350 | ||
351 | /* | |
352 | * Get the device type information | |
353 | */ | |
354 | if (scsi_inquire(st->sc_link, &inqbuf, | |
355 | SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT) != 0) { | |
98639498 | 356 | printf("st%d: couldn't get device type, using default\n", unit); |
a0becc21 NW |
357 | return; |
358 | } | |
519fb2b7 RG |
359 | if ((inqbuf.version & SID_ANSII) == 0) { |
360 | /* | |
361 | * If not advanced enough, use default values | |
362 | */ | |
363 | strncpy(manu, "pre-scsi", 8); | |
364 | manu[8] = 0; | |
365 | strncpy(model, " unknown model ", 16); | |
366 | model[16] = 0; | |
367 | strncpy(version, "????", 4); | |
368 | version[4] = 0; | |
369 | } else { | |
370 | strncpy(manu, inqbuf.vendor, 8); | |
371 | manu[8] = 0; | |
372 | strncpy(model, inqbuf.product, 16); | |
373 | model[16] = 0; | |
374 | strncpy(version, inqbuf.revision, 4); | |
375 | version[4] = 0; | |
a0becc21 | 376 | } |
519fb2b7 RG |
377 | |
378 | /* | |
379 | * Load the parameters for this kind of device, so we | |
380 | * treat it as appropriate for each operating mode. | |
381 | * Only check the number of characters in the array's | |
382 | * model entry, not the entire model string returned. | |
383 | */ | |
a0becc21 | 384 | finger = gallery; |
519fb2b7 | 385 | while (finger->name) { |
a0becc21 | 386 | model_len = 0; |
519fb2b7 | 387 | while (finger->model[model_len] && (model_len < 32)) { |
a0becc21 NW |
388 | model2[model_len] = model[model_len]; |
389 | model_len++; | |
390 | } | |
391 | model2[model_len] = 0; | |
519fb2b7 RG |
392 | if ((strcmp(manu, finger->manu) == 0) |
393 | && (strcmp(model2, finger->model) == 0 || | |
394 | strcmp("????????????????", finger->model) == 0) | |
395 | && (strcmp(version, finger->version) == 0 || | |
396 | strcmp("????", finger->version) == 0)) { | |
397 | printf("st%d: %s is a known rogue\n", unit, finger->name); | |
398 | st->rogues = finger; | |
399 | st->drive_quirks = finger->quirks; | |
400 | st->quirks = finger->quirks; /*start value */ | |
401 | st_loadquirks(st); | |
a0becc21 | 402 | break; |
519fb2b7 | 403 | } else { |
a0becc21 NW |
404 | finger++; /* go to next suspect */ |
405 | } | |
406 | } | |
407 | } | |
15637ed4 | 408 | |
519fb2b7 RG |
409 | /* |
410 | * initialise the subdevices to the default (QUIRK) state. | |
411 | * this will remove any setting made by the system operator or previous | |
412 | * operations. | |
413 | */ | |
414 | void | |
415 | st_loadquirks(st) | |
416 | struct st_data *st; | |
417 | { | |
418 | int i; | |
419 | struct modes *mode; | |
420 | struct modes *mode2; | |
421 | ||
422 | if (!st->rogues) | |
423 | return; | |
424 | mode = st->rogues->modes; | |
425 | mode2 = st->modes; | |
426 | for (i = 0; i < 4; i++) { | |
427 | bzero(mode2, sizeof(struct modes)); | |
428 | st->modeflags[i] &= ~(BLKSIZE_SET_BY_QUIRK | |
429 | | DENSITY_SET_BY_QUIRK | |
430 | | BLKSIZE_SET_BY_USER | |
431 | | DENSITY_SET_BY_USER); | |
432 | if (mode->blksiz && ((mode->quirks | st->drive_quirks) | |
433 | & (ST_Q_FORCE_FIXED_MODE))) { | |
434 | mode2->blksiz = mode->blksiz; | |
435 | st->modeflags[i] |= BLKSIZE_SET_BY_QUIRK; | |
436 | } else { | |
437 | if ((mode->quirks | st->drive_quirks) | |
438 | & ST_Q_FORCE_VAR_MODE) { | |
439 | mode2->blksiz = 0; | |
440 | st->modeflags[i] |= BLKSIZE_SET_BY_QUIRK; | |
441 | } | |
442 | } | |
443 | if (mode->density) { | |
444 | mode2->density = mode->density; | |
445 | st->modeflags[i] |= DENSITY_SET_BY_QUIRK; | |
446 | } | |
447 | mode++; | |
448 | mode2++; | |
449 | } | |
450 | } | |
451 | ||
452 | /* | |
453 | * open the device. | |
454 | */ | |
455 | errval | |
fca1f689 | 456 | stopen(dev, flags) |
519fb2b7 RG |
457 | dev_t dev; |
458 | u_int32 flags; | |
15637ed4 | 459 | { |
519fb2b7 RG |
460 | u_int32 unit, mode, dsty; |
461 | errval errno = 0; | |
15637ed4 | 462 | struct st_data *st; |
519fb2b7 | 463 | struct scsi_link *sc_link; |
15637ed4 RG |
464 | unit = UNIT(dev); |
465 | mode = MODE(dev); | |
466 | dsty = DSTY(dev); | |
15637ed4 | 467 | |
519fb2b7 RG |
468 | /* |
469 | * Check the unit is legal | |
470 | */ | |
471 | if (unit >= NST) { | |
472 | return (ENXIO); | |
15637ed4 | 473 | } |
d4284689 | 474 | st = st_data[unit]; |
519fb2b7 RG |
475 | /* |
476 | * Make sure the device has been initialised | |
477 | */ | |
d4284689 | 478 | if ((st == NULL) || (!(st->flags & ST_INITIALIZED))) |
519fb2b7 RG |
479 | return (ENXIO); |
480 | ||
481 | sc_link = st->sc_link; | |
482 | SC_DEBUG(sc_link, SDEV_DB1, ("open: dev=0x%x (unit %d (of %d))\n" | |
483 | ,dev, unit, NST)); | |
484 | /* | |
485 | * Only allow one at a time | |
486 | */ | |
487 | if (st->flags & ST_OPEN) { | |
46d39670 | 488 | return (EBUSY); |
a0becc21 | 489 | } |
519fb2b7 RG |
490 | /* |
491 | * Throw out a dummy instruction to catch 'Unit attention | |
492 | * errors (the error handling will invalidate all our | |
493 | * device info if we get one, but otherwise, ignore it) | |
494 | */ | |
495 | scsi_test_unit_ready(sc_link, SCSI_SILENT); | |
496 | ||
497 | sc_link->flags |= SDEV_OPEN; /* unit attn are now errors */ | |
498 | /* | |
499 | * If the mode is 3 (e.g. minor = 3,7,11,15) | |
500 | * then the device has been openned to set defaults | |
501 | * This mode does NOT ALLOW I/O, only ioctls | |
502 | */ | |
503 | if (mode == CTLMODE) | |
504 | return 0; | |
505 | ||
506 | /* | |
507 | * Check that the device is ready to use (media loaded?) | |
508 | * This time take notice of the return result | |
509 | */ | |
510 | if (errno = (scsi_test_unit_ready(sc_link, 0))) { | |
511 | printf("st%d: not ready\n", unit); | |
512 | st_unmount(unit, NOEJECT); | |
513 | return (errno); | |
15637ed4 | 514 | } |
519fb2b7 RG |
515 | /* |
516 | * if it's a different mode, or if the media has been | |
517 | * invalidated, unmount the tape from the previous | |
518 | * session but continue with open processing | |
519 | */ | |
520 | if ((st->last_dsty != dsty) | |
521 | || (!(sc_link->flags & SDEV_MEDIA_LOADED))) { | |
522 | st_unmount(unit, NOEJECT); | |
0269d546 | 523 | } |
519fb2b7 RG |
524 | /* |
525 | * If we are not mounted, then we should start a new | |
526 | * mount session. | |
527 | */ | |
528 | if (!(st->flags & ST_MOUNTED)) { | |
529 | st_mount_tape(dev, flags); | |
530 | st->last_dsty = dsty; | |
fca1f689 | 531 | } |
519fb2b7 RG |
532 | /* |
533 | * Make sure that a tape opened in write-only mode will have | |
534 | * file marks written on it when closed, even if not written to. | |
535 | * This is for SUN compatibility | |
536 | */ | |
fca1f689 RG |
537 | if ((flags & O_ACCMODE) == FWRITE) |
538 | st->flags |= ST_WRITTEN; | |
539 | ||
519fb2b7 | 540 | SC_DEBUG(sc_link, SDEV_DB2, ("Open complete\n")); |
15637ed4 RG |
541 | |
542 | st->flags |= ST_OPEN; | |
519fb2b7 | 543 | return (0); |
15637ed4 RG |
544 | } |
545 | ||
519fb2b7 RG |
546 | /* |
547 | * close the device.. only called if we are the LAST | |
548 | * occurence of an open device | |
549 | */ | |
550 | errval | |
15637ed4 | 551 | stclose(dev) |
519fb2b7 | 552 | dev_t dev; |
15637ed4 | 553 | { |
519fb2b7 RG |
554 | unsigned char unit, mode; |
555 | struct st_data *st; | |
556 | struct scsi_link *sc_link; | |
15637ed4 RG |
557 | |
558 | unit = UNIT(dev); | |
559 | mode = MODE(dev); | |
d4284689 | 560 | st = st_data[unit]; |
519fb2b7 RG |
561 | sc_link = st->sc_link; |
562 | ||
563 | SC_DEBUG(sc_link, SDEV_DB1, ("closing\n")); | |
564 | if ((st->flags & (ST_WRITTEN | ST_FM_WRITTEN)) == ST_WRITTEN) | |
565 | st_write_filemarks(unit, 1, 0); | |
566 | switch (mode & 0x3) { | |
567 | case 0: | |
568 | case 3: /* for now */ | |
569 | st_unmount(unit, NOEJECT); | |
15637ed4 | 570 | break; |
519fb2b7 RG |
571 | case 1: /*leave mounted unless media seems to have been removed */ |
572 | if (!(sc_link->flags & SDEV_MEDIA_LOADED)) { | |
573 | st_unmount(unit, NOEJECT); | |
574 | } | |
15637ed4 | 575 | break; |
519fb2b7 RG |
576 | case 2: |
577 | st_unmount(unit, EJECT); | |
15637ed4 | 578 | break; |
15637ed4 | 579 | } |
519fb2b7 RG |
580 | sc_link->flags &= ~SDEV_OPEN; |
581 | st->flags &= ~ST_OPEN; | |
582 | return (0); | |
15637ed4 RG |
583 | } |
584 | ||
519fb2b7 RG |
585 | /* |
586 | * Start a new mount session. | |
587 | * Copy in all the default parameters from the selected device mode. | |
588 | * and try guess any that seem to be defaulted. | |
589 | */ | |
590 | errval | |
591 | st_mount_tape(dev, flags) | |
592 | dev_t dev; | |
593 | u_int32 flags; | |
a0becc21 | 594 | { |
519fb2b7 RG |
595 | u_int32 unit, mode, dsty; |
596 | struct st_data *st; | |
597 | struct scsi_link *sc_link; | |
598 | errval errno = 0; | |
a0becc21 | 599 | |
519fb2b7 RG |
600 | unit = UNIT(dev); |
601 | mode = MODE(dev); | |
602 | dsty = DSTY(dev); | |
603 | st = st_data[unit]; | |
604 | sc_link = st->sc_link; | |
605 | ||
606 | if (st->flags & ST_MOUNTED) | |
607 | return 0; | |
608 | ||
609 | SC_DEBUG(sc_link, SDEV_DB1, ("mounting\n ")); | |
610 | st->flags |= ST_NEW_MOUNT; | |
611 | st->quirks = st->drive_quirks | st->modes[dsty].quirks; | |
612 | /* | |
613 | * If the media is new, then make sure we give it a chance to | |
614 | * to do a 'load' instruction. ( We assume it is new) | |
615 | */ | |
616 | if (errno = st_load(unit, LD_LOAD, 0)) { | |
617 | return (errno); | |
d4284689 | 618 | } |
519fb2b7 RG |
619 | /* |
620 | * Throw another dummy instruction to catch | |
621 | * 'Unit attention' errors. Some drives appear to give | |
622 | * these after doing a Load instruction. | |
623 | * (noteably some DAT drives) | |
624 | */ | |
625 | scsi_test_unit_ready(sc_link, SCSI_SILENT); | |
626 | ||
627 | /* | |
628 | * Some devices can't tell you much until they have been | |
629 | * asked to look at the media. This quirk does this. | |
630 | */ | |
631 | if (st->quirks & ST_Q_SNS_HLP) { | |
632 | if (errno = st_touch_tape(unit)) | |
633 | return errno; | |
634 | } | |
635 | /* | |
636 | * Load the physical device parameters | |
637 | * loads: blkmin, blkmax | |
638 | */ | |
639 | if (errno = st_rd_blk_lim(unit, 0)) { | |
640 | return errno; | |
641 | } | |
642 | /* | |
643 | * Load the media dependent parameters | |
644 | * includes: media_blksiz,media_density,numblks | |
645 | * As we have a tape in, it should be reflected here. | |
646 | * If not you may need the "quirk" above. | |
647 | */ | |
648 | if (errno = st_mode_sense(unit, 0)) { | |
649 | return errno; | |
650 | } | |
651 | /* | |
652 | * If we have gained a permanent density from somewhere, | |
653 | * then use it in preference to the one supplied by | |
654 | * default by the driver. | |
655 | */ | |
656 | if (st->modeflags[dsty] & (DENSITY_SET_BY_QUIRK | DENSITY_SET_BY_USER)) { | |
657 | st->density = st->modes[dsty].density; | |
658 | } else { | |
659 | st->density = st->media_density; | |
660 | } | |
661 | /* | |
662 | * If we have gained a permanent blocksize | |
663 | * then use it in preference to the one supplied by | |
664 | * default by the driver. | |
665 | */ | |
666 | st->flags &= ~ST_FIXEDBLOCKS; | |
667 | if (st->modeflags[dsty] & (BLKSIZE_SET_BY_QUIRK | BLKSIZE_SET_BY_USER)) { | |
668 | st->blksiz = st->modes[dsty].blksiz; | |
669 | if (st->blksiz) { | |
670 | st->flags |= ST_FIXEDBLOCKS; | |
671 | } | |
672 | } else { | |
673 | if (errno = st_decide_mode(unit, FALSE)) { | |
674 | return errno; | |
675 | } | |
d4284689 | 676 | } |
519fb2b7 RG |
677 | if (errno = st_mode_select(unit, 0)) { |
678 | printf("st%d: Cannot set selected mode", unit); | |
679 | return errno; | |
680 | } | |
681 | scsi_prevent(sc_link, PR_PREVENT, 0); /* who cares if it fails? */ | |
682 | st->flags &= ~ST_NEW_MOUNT; | |
683 | st->flags |= ST_MOUNTED; | |
684 | sc_link->flags |= SDEV_MEDIA_LOADED; /* move earlier? */ | |
a0becc21 | 685 | |
519fb2b7 RG |
686 | return 0; |
687 | } | |
688 | ||
689 | /* | |
690 | * End the present mount session. | |
691 | * Rewind, and optionally eject the tape. | |
692 | * Reset various flags to indicate that all new | |
693 | * operations require another mount operation | |
694 | */ | |
695 | void | |
696 | st_unmount(int unit, boolean eject) | |
697 | { | |
698 | struct st_data *st = st_data[unit]; | |
699 | struct scsi_link *sc_link = st->sc_link; | |
700 | int32 nmarks; | |
701 | ||
702 | if (!(st->flags & ST_MOUNTED)) | |
703 | return; | |
704 | SC_DEBUG(sc_link, SDEV_DB1, ("unmounting\n")); | |
705 | st_chkeod(unit, FALSE, &nmarks, SCSI_SILENT); | |
706 | st_rewind(unit, FALSE, SCSI_SILENT); | |
707 | scsi_prevent(sc_link, PR_ALLOW, SCSI_SILENT); | |
708 | if (eject) { | |
709 | st_load(unit, LD_UNLOAD, SCSI_SILENT); | |
710 | } | |
711 | st->flags &= ~(ST_MOUNTED | ST_NEW_MOUNT); | |
712 | sc_link->flags &= ~SDEV_MEDIA_LOADED; | |
713 | } | |
714 | ||
715 | /* | |
716 | * Given all we know about the device, media, mode, 'quirks' and | |
717 | * initial operation, make a decision as to how we should be set | |
718 | * to run (regarding blocking and EOD marks) | |
719 | */ | |
720 | errval | |
721 | st_decide_mode(unit, first_read) | |
722 | u_int32 unit; | |
723 | boolean first_read; | |
724 | { | |
725 | struct st_data *st = st_data[unit]; | |
726 | #ifdef SCSIDEBUG | |
727 | struct scsi_link *sc_link = st->sc_link; | |
728 | #endif | |
729 | ||
730 | SC_DEBUG(sc_link, SDEV_DB2, ("starting block mode decision\n")); | |
731 | ||
732 | /* | |
733 | * If the user hasn't already specified fixed or variable-length | |
734 | * blocks and the block size (zero if variable-length), we'll | |
735 | * have to try to figure them out ourselves. | |
736 | * | |
737 | * Our first shot at a method is, "The quirks made me do it!" | |
738 | */ | |
fde1aeb2 | 739 | switch ((int)(st->quirks & (ST_Q_FORCE_FIXED_MODE | ST_Q_FORCE_VAR_MODE))) { |
519fb2b7 RG |
740 | case (ST_Q_FORCE_FIXED_MODE | ST_Q_FORCE_VAR_MODE): |
741 | printf("st%d: bad quirks\n", unit); | |
d4284689 | 742 | return (EINVAL); |
519fb2b7 | 743 | case ST_Q_FORCE_FIXED_MODE: /*specified fixed, but not what size */ |
a0becc21 | 744 | st->flags |= ST_FIXEDBLOCKS; |
0269d546 | 745 | if (st->blkmin && (st->blkmin == st->blkmax)) |
d4284689 | 746 | st->blksiz = st->blkmin; |
519fb2b7 | 747 | else if (st->media_blksiz > 0) |
a0becc21 | 748 | st->blksiz = st->media_blksiz; |
a0becc21 | 749 | else |
d4284689 | 750 | st->blksiz = DEF_FIXED_BSIZE; |
519fb2b7 RG |
751 | SC_DEBUG(sc_link, SDEV_DB3, ("Quirks force fixed mode(%d)\n", |
752 | st->blksiz)); | |
d4284689 | 753 | goto done; |
519fb2b7 | 754 | case ST_Q_FORCE_VAR_MODE: |
a0becc21 NW |
755 | st->flags &= ~ST_FIXEDBLOCKS; |
756 | st->blksiz = 0; | |
519fb2b7 | 757 | SC_DEBUG(sc_link, SDEV_DB3, ("Quirks force variable mode\n")); |
d4284689 | 758 | goto done; |
a0becc21 | 759 | } |
519fb2b7 RG |
760 | /* |
761 | * If the drive can only handle fixed-length blocks and only at | |
762 | * one size, perhaps we should just do that. | |
763 | */ | |
764 | if (st->blkmin && (st->blkmin == st->blkmax)) { | |
d4284689 RG |
765 | st->flags |= ST_FIXEDBLOCKS; |
766 | st->blksiz = st->blkmin; | |
519fb2b7 RG |
767 | SC_DEBUG(sc_link, SDEV_DB3, |
768 | ("blkmin == blkmax of %d\n", st->blkmin)); | |
d4284689 RG |
769 | goto done; |
770 | } | |
519fb2b7 RG |
771 | /* |
772 | * If the tape density mandates (or even suggests) use of fixed | |
773 | * or variable-length blocks, comply. | |
774 | */ | |
fde1aeb2 | 775 | switch ((int)st->density) { |
519fb2b7 RG |
776 | case HALFINCH_800: |
777 | case HALFINCH_1600: | |
778 | case HALFINCH_6250: | |
779 | case DDS: | |
d4284689 RG |
780 | st->flags &= ~ST_FIXEDBLOCKS; |
781 | st->blksiz = 0; | |
519fb2b7 | 782 | SC_DEBUG(sc_link, SDEV_DB3, ("density specified variable\n")); |
d4284689 | 783 | goto done; |
519fb2b7 RG |
784 | case QIC_11: |
785 | case QIC_24: | |
786 | case QIC_120: | |
787 | case QIC_150: | |
788 | case QIC_525: | |
789 | case QIC_1320: | |
d4284689 | 790 | st->flags |= ST_FIXEDBLOCKS; |
519fb2b7 | 791 | if (st->media_blksiz > 0) { |
d4284689 | 792 | st->blksiz = st->media_blksiz; |
519fb2b7 | 793 | } else { |
d4284689 | 794 | st->blksiz = DEF_FIXED_BSIZE; |
519fb2b7 RG |
795 | } |
796 | SC_DEBUG(sc_link, SDEV_DB3, ("density specified fixed\n")); | |
d4284689 RG |
797 | goto done; |
798 | } | |
519fb2b7 RG |
799 | /* |
800 | * If we're about to read the tape, perhaps we should choose | |
801 | * fixed or variable-length blocks and block size according to | |
802 | * what the drive found on the tape. | |
803 | */ | |
804 | if (first_read | |
805 | && (!(st->quirks & ST_Q_BLKSIZ) | |
806 | || (st->media_blksiz == 0) | |
807 | || (st->media_blksiz == DEF_FIXED_BSIZE) | |
808 | || (st->media_blksiz == 1024))) { | |
809 | if (st->media_blksiz == 0) { | |
d4284689 | 810 | st->flags &= ~ST_FIXEDBLOCKS; |
519fb2b7 | 811 | } else { |
d4284689 | 812 | st->flags |= ST_FIXEDBLOCKS; |
519fb2b7 | 813 | } |
d4284689 | 814 | st->blksiz = st->media_blksiz; |
519fb2b7 RG |
815 | SC_DEBUG(sc_link, SDEV_DB3, |
816 | ("Used media_blksiz of %d\n", st->media_blksiz)); | |
d4284689 RG |
817 | goto done; |
818 | } | |
519fb2b7 RG |
819 | /* |
820 | * We're getting no hints from any direction. Choose variable- | |
821 | * length blocks arbitrarily. | |
822 | */ | |
0269d546 RG |
823 | st->flags &= ~ST_FIXEDBLOCKS; |
824 | st->blksiz = 0; | |
519fb2b7 | 825 | SC_DEBUG(sc_link, SDEV_DB3, ("Give up and default to variable mode\n")); |
d4284689 | 826 | done: |
519fb2b7 RG |
827 | |
828 | /* | |
829 | * Decide whether or not to write two file marks to signify end- | |
830 | * of-data. Make the decision as a function of density. If | |
831 | * the decision is not to use a second file mark, the SCSI BLANK | |
832 | * CHECK condition code will be recognized as end-of-data when | |
833 | * first read. | |
834 | * (I think this should be a by-product of fixed/variable..julian) | |
835 | */ | |
fde1aeb2 | 836 | switch ((int)st->density) { |
519fb2b7 RG |
837 | /* case 8 mm: What is the SCSI density code for 8 mm, anyway? */ |
838 | case QIC_11: | |
839 | case QIC_24: | |
840 | case QIC_120: | |
841 | case QIC_150: | |
842 | case QIC_525: | |
843 | case QIC_1320: | |
844 | st->flags &= ~ST_2FM_AT_EOD; | |
845 | break; | |
846 | default: | |
847 | st->flags |= ST_2FM_AT_EOD; | |
848 | } | |
849 | return 0; | |
d4284689 | 850 | } |
15637ed4 | 851 | |
519fb2b7 RG |
852 | /* |
853 | * trim the size of the transfer if needed, | |
854 | * called by physio | |
855 | * basically the smaller of our min and the scsi driver's | |
856 | * minphys | |
857 | */ | |
858 | void | |
859 | stminphys(bp) | |
860 | struct buf *bp; | |
15637ed4 | 861 | { |
519fb2b7 | 862 | (*(st_data[UNIT(bp->b_dev)]->sc_link->adapter->scsi_minphys)) (bp); |
15637ed4 RG |
863 | } |
864 | ||
519fb2b7 RG |
865 | /* |
866 | * Actually translate the requested transfer into | |
867 | * one the physical driver can understand | |
868 | * The transfer is described by a buf and will include | |
869 | * only one physical transfer. | |
870 | */ | |
871 | void | |
872 | ststrategy(bp) | |
873 | struct buf *bp; | |
15637ed4 | 874 | { |
519fb2b7 | 875 | struct buf **dp; |
15637ed4 | 876 | unsigned char unit; |
519fb2b7 | 877 | u_int32 opri; |
d4284689 | 878 | struct st_data *st; |
15637ed4 RG |
879 | |
880 | ststrats++; | |
881 | unit = UNIT((bp->b_dev)); | |
d4284689 | 882 | st = st_data[unit]; |
519fb2b7 RG |
883 | SC_DEBUG(st->sc_link, SDEV_DB1, |
884 | (" strategy: %d bytes @ blk%d\n", bp->b_bcount, bp->b_blkno)); | |
885 | /* | |
886 | * If it's a null transfer, return immediatly | |
887 | */ | |
888 | if (bp->b_bcount == 0) { | |
15637ed4 RG |
889 | goto done; |
890 | } | |
519fb2b7 RG |
891 | /* |
892 | * Odd sized request on fixed drives are verboten | |
893 | */ | |
894 | if (st->flags & ST_FIXEDBLOCKS) { | |
895 | if (bp->b_bcount % st->blksiz) { | |
a0becc21 | 896 | printf("st%d: bad request, must be multiple of %d\n", |
519fb2b7 | 897 | unit, st->blksiz); |
a0becc21 NW |
898 | bp->b_error = EIO; |
899 | goto bad; | |
900 | } | |
901 | } | |
519fb2b7 RG |
902 | /* |
903 | * as are out-of-range requests on variable drives. | |
904 | */ | |
905 | else if (bp->b_bcount < st->blkmin || bp->b_bcount > st->blkmax) { | |
d4284689 | 906 | printf("st%d: bad request, must be between %d and %d\n", |
519fb2b7 | 907 | unit, st->blkmin, st->blkmax); |
15637ed4 RG |
908 | bp->b_error = EIO; |
909 | goto bad; | |
910 | } | |
15637ed4 | 911 | stminphys(bp); |
15637ed4 | 912 | opri = splbio(); |
15637ed4 | 913 | |
8387479d DG |
914 | /* |
915 | * Use a bounce buffer if necessary | |
916 | */ | |
917 | #ifndef NOBOUNCE | |
918 | if (st->sc_link->flags & SDEV_BOUNCE) | |
919 | vm_bounce_alloc(bp); | |
920 | #endif | |
921 | ||
519fb2b7 RG |
922 | /* |
923 | * Place it in the queue of activities for this tape | |
924 | * at the end (a bit silly because we only have on user.. | |
925 | * (but it could fork() )) | |
926 | */ | |
d4284689 | 927 | dp = &(st->buf_queue); |
519fb2b7 | 928 | while (*dp) { |
d4284689 | 929 | dp = &((*dp)->b_actf); |
519fb2b7 | 930 | } |
d4284689 | 931 | *dp = bp; |
2aecffae | 932 | bp->b_actf = NULL; |
15637ed4 | 933 | |
519fb2b7 RG |
934 | /* |
935 | * Tell the device to get going on the transfer if it's | |
936 | * not doing anything, otherwise just wait for completion | |
937 | * (All a bit silly if we're only allowing 1 open but..) | |
938 | */ | |
15637ed4 RG |
939 | ststart(unit); |
940 | ||
941 | splx(opri); | |
942 | return; | |
943 | bad: | |
944 | bp->b_flags |= B_ERROR; | |
945 | done: | |
519fb2b7 RG |
946 | /* |
947 | * Correctly set the buf to indicate a completed xfer | |
948 | */ | |
15637ed4 RG |
949 | iodone(bp); |
950 | return; | |
951 | } | |
952 | ||
519fb2b7 RG |
953 | /* |
954 | * ststart looks to see if there is a buf waiting for the device | |
955 | * and that the device is not already busy. If both are true, | |
956 | * It dequeues the buf and creates a scsi command to perform the | |
957 | * transfer required. The transfer request will call scsi_done | |
958 | * on completion, which will in turn call this routine again | |
959 | * so that the next queued transfer is performed. | |
960 | * The bufs are queued by the strategy routine (ststrategy) | |
961 | * | |
962 | * This routine is also called after other non-queued requests | |
963 | * have been made of the scsi driver, to ensure that the queue | |
964 | * continues to be drained. | |
965 | * ststart() is called at splbio | |
966 | */ | |
967 | void | |
968 | ststart(unit) | |
969 | u_int32 unit; | |
970 | { | |
971 | struct st_data *st = st_data[unit]; | |
972 | struct scsi_link *sc_link = st->sc_link; | |
973 | register struct buf *bp = 0; | |
974 | struct scsi_rw_tape cmd; | |
975 | u_int32 flags; | |
976 | ||
977 | SC_DEBUG(sc_link, SDEV_DB2, ("ststart ")); | |
978 | /* | |
979 | * See if there is a buf to do and we are not already | |
980 | * doing one | |
981 | */ | |
982 | while (sc_link->opennings != 0) { | |
983 | ||
984 | /* if a special awaits, let it proceed first */ | |
985 | if (sc_link->flags & SDEV_WAITING) { | |
46d39670 | 986 | sc_link->flags &= ~SDEV_WAITING; |
519fb2b7 RG |
987 | wakeup((caddr_t)sc_link); |
988 | return; | |
989 | } | |
990 | if ((bp = st->buf_queue) == NULL) { | |
991 | return; /* no work to bother with */ | |
992 | } | |
993 | st->buf_queue = bp->b_actf; | |
994 | ||
995 | /* | |
996 | * if the device has been unmounted byt the user | |
997 | * then throw away all requests until done | |
998 | */ | |
999 | if ((!(st->flags & ST_MOUNTED)) | |
1000 | || (!(sc_link->flags & SDEV_MEDIA_LOADED))) { | |
1001 | /* make sure that one implies the other.. */ | |
1002 | sc_link->flags &= ~SDEV_MEDIA_LOADED; | |
1003 | goto badnews; | |
1004 | } | |
1005 | /* | |
1006 | * only FIXEDBLOCK devices have pending operations | |
1007 | */ | |
1008 | if (st->flags & ST_FIXEDBLOCKS) { | |
1009 | /* | |
1010 | * If we are at a filemark but have not reported it yet | |
1011 | * then we should report it now | |
1012 | */ | |
1013 | if (st->flags & ST_AT_FILEMARK) { | |
1014 | if ((bp->b_flags & B_READ) == B_WRITE) { | |
1015 | /* | |
1016 | * Handling of ST_AT_FILEMARK in | |
1017 | * st_space will fill in the right file | |
1018 | * mark count. | |
1019 | * Back up over filemark | |
1020 | */ | |
1021 | if (st_space(unit, 0, SP_FILEMARKS, 0) != | |
1022 | ESUCCESS) | |
1023 | goto badnews; | |
1024 | } else { | |
1025 | bp->b_resid = bp->b_bcount; | |
1026 | bp->b_error = 0; | |
1027 | bp->b_flags &= ~B_ERROR; | |
1028 | st->flags &= ~ST_AT_FILEMARK; | |
1029 | biodone(bp); | |
1030 | continue; /* seek more work */ | |
1031 | } | |
1032 | } | |
1033 | /* | |
1034 | * If we are at EIO (e.g. EOM) but have not reported it | |
1035 | * yet then we should report it now | |
1036 | */ | |
1037 | if (st->flags & ST_EIO_PENDING) { | |
1038 | bp->b_resid = bp->b_bcount; | |
1039 | bp->b_error = EIO; | |
1040 | bp->b_flags |= B_ERROR; | |
1041 | st->flags &= ~ST_EIO_PENDING; | |
1042 | biodone(bp); | |
1043 | continue; /* seek more work */ | |
1044 | } | |
1045 | } | |
1046 | /* | |
1047 | * Fill out the scsi command | |
1048 | */ | |
1049 | bzero(&cmd, sizeof(cmd)); | |
1050 | if ((bp->b_flags & B_READ) == B_WRITE) { | |
1051 | cmd.op_code = WRITE_COMMAND_TAPE; | |
1052 | st->flags &= ~ST_FM_WRITTEN; | |
1053 | st->flags |= ST_WRITTEN; | |
1054 | flags = SCSI_DATA_OUT; | |
1055 | } else { | |
1056 | cmd.op_code = READ_COMMAND_TAPE; | |
1057 | flags = SCSI_DATA_IN; | |
1058 | } | |
1059 | /* | |
1060 | * Handle "fixed-block-mode" tape drives by using the | |
1061 | * block count instead of the length. | |
1062 | */ | |
1063 | if (st->flags & ST_FIXEDBLOCKS) { | |
1064 | cmd.byte2 |= SRWT_FIXED; | |
1065 | lto3b(bp->b_bcount / st->blksiz, cmd.len); | |
1066 | } else { | |
1067 | lto3b(bp->b_bcount, cmd.len); | |
1068 | } | |
1069 | /* | |
1070 | * go ask the adapter to do all this for us | |
1071 | */ | |
1072 | if (scsi_scsi_cmd(sc_link, | |
1073 | (struct scsi_generic *) &cmd, | |
1074 | sizeof(cmd), | |
1075 | (u_char *) bp->b_un.b_addr, | |
1076 | bp->b_bcount, | |
1077 | 0, /* can't retry a read on a tape really */ | |
1078 | 100000, | |
1079 | bp, | |
1080 | flags | SCSI_NOSLEEP) == SUCCESSFULLY_QUEUED) { | |
1081 | stqueues++; | |
1082 | } else { | |
1083 | badnews: | |
1084 | printf("st%d: oops not queued\n", unit); | |
1085 | bp->b_flags |= B_ERROR; | |
1086 | bp->b_error = EIO; | |
1087 | biodone(bp); | |
1088 | } | |
1089 | } /* go back and see if we can cram more work in.. */ | |
1090 | } | |
15637ed4 | 1091 | |
519fb2b7 RG |
1092 | /* |
1093 | * Perform special action on behalf of the user; | |
1094 | * knows about the internals of this device | |
1095 | */ | |
1096 | errval | |
1097 | stioctl(dev, cmd, arg, flag) | |
1098 | dev_t dev; | |
1099 | int cmd; | |
1100 | caddr_t arg; | |
1101 | int flag; | |
d4284689 | 1102 | { |
519fb2b7 | 1103 | errval errcode = 0; |
d4284689 | 1104 | unsigned char unit; |
519fb2b7 RG |
1105 | u_int32 number, flags, dsty; |
1106 | struct st_data *st; | |
1107 | u_int32 hold_blksiz; | |
1108 | u_int32 hold_density; | |
1109 | int32 nmarks; | |
1110 | struct mtop *mt = (struct mtop *) arg; | |
1111 | ||
1112 | /* | |
1113 | * Find the device that the user is talking about | |
1114 | */ | |
1115 | flags = 0; /* give error messages, act on errors etc. */ | |
15637ed4 | 1116 | unit = UNIT(dev); |
0269d546 | 1117 | dsty = DSTY(dev); |
519fb2b7 RG |
1118 | st = st_data[unit]; |
1119 | hold_blksiz = st->blksiz; | |
1120 | hold_density = st->density; | |
15637ed4 | 1121 | |
519fb2b7 | 1122 | switch (cmd) { |
15637ed4 RG |
1123 | |
1124 | case MTIOCGET: | |
519fb2b7 RG |
1125 | { |
1126 | struct mtget *g = (struct mtget *) arg; | |
1127 | ||
1128 | SC_DEBUG(st->sc_link, SDEV_DB1, ("[ioctl: get status]\n")); | |
1129 | bzero(g, sizeof(struct mtget)); | |
1130 | g->mt_type = 0x7; /* Ultrix compat *//*? */ | |
1131 | g->mt_density = st->density; | |
1132 | g->mt_blksiz = st->blksiz; | |
1133 | g->mt_density0 = st->modes[0].density; | |
1134 | g->mt_density1 = st->modes[1].density; | |
1135 | g->mt_density2 = st->modes[2].density; | |
1136 | g->mt_density3 = st->modes[3].density; | |
1137 | g->mt_blksiz0 = st->modes[0].blksiz; | |
1138 | g->mt_blksiz1 = st->modes[1].blksiz; | |
1139 | g->mt_blksiz2 = st->modes[2].blksiz; | |
1140 | g->mt_blksiz3 = st->modes[3].blksiz; | |
1141 | break; | |
1142 | } | |
15637ed4 | 1143 | case MTIOCTOP: |
519fb2b7 | 1144 | { |
15637ed4 | 1145 | |
519fb2b7 RG |
1146 | SC_DEBUG(st->sc_link, SDEV_DB1, ("[ioctl: op=0x%x count=0x%x]\n", |
1147 | mt->mt_op, mt->mt_count)); | |
15637ed4 | 1148 | |
519fb2b7 RG |
1149 | /* compat: in U*x it is a short */ |
1150 | number = mt->mt_count; | |
1151 | switch ((short) (mt->mt_op)) { | |
1152 | case MTWEOF: /* write an end-of-file record */ | |
1153 | errcode = st_write_filemarks(unit, number, flags); | |
d4284689 | 1154 | break; |
519fb2b7 RG |
1155 | case MTBSF: /* backward space file */ |
1156 | number = -number; | |
1157 | case MTFSF: /* forward space file */ | |
1158 | errcode = st_chkeod(unit, FALSE, &nmarks, flags); | |
1159 | if (errcode == ESUCCESS) | |
1160 | errcode = st_space(unit, number - nmarks, | |
1161 | SP_FILEMARKS, flags); | |
1162 | break; | |
1163 | case MTBSR: /* backward space record */ | |
1164 | number = -number; | |
1165 | case MTFSR: /* forward space record */ | |
1166 | errcode = st_chkeod(unit, TRUE, &nmarks, flags); | |
1167 | if (errcode == ESUCCESS) | |
1168 | errcode = st_space(unit, number, SP_BLKS, flags); | |
1169 | break; | |
1170 | case MTREW: /* rewind */ | |
1171 | errcode = st_rewind(unit, FALSE, flags); | |
1172 | break; | |
1173 | case MTOFFL: /* rewind and put the drive offline */ | |
1174 | st_unmount(unit, EJECT); | |
1175 | break; | |
1176 | case MTNOP: /* no operation, sets status only */ | |
1177 | case MTCACHE: /* enable controller cache */ | |
1178 | case MTNOCACHE: /* disable controller cache */ | |
1179 | break; | |
1180 | case MTSETBSIZ: /* Set block size for device */ | |
1181 | #ifdef NOTYET | |
1182 | if (!(st->flags & ST_NEW_MOUNT)) { | |
1183 | uprintf("re-mount tape before changing blocksize"); | |
0269d546 RG |
1184 | errcode = EINVAL; |
1185 | break; | |
1186 | } | |
519fb2b7 RG |
1187 | #endif |
1188 | if (number == 0) { | |
1189 | st->flags &= ~ST_FIXEDBLOCKS; | |
1190 | } else { | |
1191 | if ((st->blkmin || st->blkmax) /* they exist */ | |
1192 | &&((number < st->blkmin | |
1193 | || number > st->blkmax))) { | |
1194 | errcode = EINVAL; | |
1195 | break; | |
1196 | } | |
1197 | st->flags |= ST_FIXEDBLOCKS; | |
1198 | } | |
1199 | st->blksiz = number; | |
1200 | st->flags |= ST_BLOCK_SET; /*XXX */ | |
1201 | goto try_new_value; | |
a0becc21 | 1202 | |
519fb2b7 RG |
1203 | case MTSETDNSTY: /* Set density for device and mode */ |
1204 | if (number > SCSI_2_MAX_DENSITY_CODE) { | |
1205 | errcode = EINVAL; | |
1206 | } else { | |
1207 | st->density = number; | |
1208 | } | |
1209 | goto try_new_value; | |
a0becc21 | 1210 | |
519fb2b7 | 1211 | default: |
869c4419 | 1212 | errcode = EINVAL; |
a0becc21 | 1213 | } |
a0becc21 | 1214 | break; |
15637ed4 | 1215 | } |
15637ed4 RG |
1216 | case MTIOCIEOT: |
1217 | case MTIOCEEOT: | |
15637ed4 | 1218 | break; |
869c4419 | 1219 | default: |
519fb2b7 RG |
1220 | if(MODE(dev) == CTLMODE) |
1221 | errcode = scsi_do_ioctl(st->sc_link,cmd,arg,flag); | |
1222 | else | |
1223 | errcode = ENOTTY; | |
1224 | break; | |
15637ed4 | 1225 | } |
869c4419 | 1226 | return errcode; |
519fb2b7 RG |
1227 | /*-----------------------------*/ |
1228 | try_new_value: | |
1229 | /* | |
1230 | * Check that the mode being asked for is aggreeable to the | |
1231 | * drive. If not, put it back the way it was. | |
1232 | */ | |
1233 | if (errcode = st_mode_select(unit, 0)) { /* put it back as it was */ | |
1234 | printf("st%d: Cannot set selected mode", unit); | |
1235 | st->density = hold_density; | |
1236 | st->blksiz = hold_blksiz; | |
1237 | if (st->blksiz) { | |
1238 | st->flags |= ST_FIXEDBLOCKS; | |
1239 | } else { | |
1240 | st->flags &= ~ST_FIXEDBLOCKS; | |
1241 | } | |
1242 | return (errcode); | |
1243 | } | |
1244 | /* | |
1245 | * As the drive liked it, if we are setting a new default, | |
1246 | * set it into the structures as such. | |
1247 | * | |
1248 | * The means for deciding this are not finalised yet | |
1249 | */ | |
1250 | if (MODE(dev) == 0x03) { | |
1251 | /* special mode */ | |
1252 | /* XXX */ | |
1253 | switch ((short) (mt->mt_op)) { | |
1254 | case MTSETBSIZ: | |
1255 | st->modes[dsty].blksiz = st->blksiz; | |
1256 | st->modeflags[dsty] |= BLKSIZE_SET_BY_USER; | |
1257 | break; | |
1258 | case MTSETDNSTY: | |
1259 | st->modes[dsty].density = st->density; | |
1260 | st->modeflags[dsty] |= DENSITY_SET_BY_USER; | |
1261 | break; | |
1262 | } | |
1263 | } | |
1264 | return 0; | |
15637ed4 RG |
1265 | } |
1266 | ||
519fb2b7 RG |
1267 | /* |
1268 | * Do a synchronous read. | |
1269 | */ | |
1270 | errval | |
1271 | st_read(unit, buf, size, flags) | |
1272 | u_int32 unit, size, flags; | |
1273 | char *buf; | |
15637ed4 | 1274 | { |
d4284689 RG |
1275 | struct scsi_rw_tape scsi_cmd; |
1276 | struct st_data *st = st_data[unit]; | |
15637ed4 | 1277 | |
519fb2b7 RG |
1278 | /* |
1279 | * If it's a null transfer, return immediatly | |
1280 | */ | |
1281 | if (size == 0) { | |
1282 | return (ESUCCESS); | |
d4284689 | 1283 | } |
d4284689 RG |
1284 | bzero(&scsi_cmd, sizeof(scsi_cmd)); |
1285 | scsi_cmd.op_code = READ_COMMAND_TAPE; | |
519fb2b7 RG |
1286 | if (st->flags & ST_FIXEDBLOCKS) { |
1287 | scsi_cmd.byte2 |= SRWT_FIXED; | |
1288 | lto3b(size / (st->blksiz ? st->blksiz : DEF_FIXED_BSIZE), | |
1289 | scsi_cmd.len); | |
1290 | } else { | |
1291 | lto3b(size, scsi_cmd.len); | |
1292 | } | |
1293 | return (scsi_scsi_cmd(st->sc_link, | |
1294 | (struct scsi_generic *) &scsi_cmd, | |
1295 | sizeof(scsi_cmd), | |
1296 | (u_char *) buf, | |
1297 | size, | |
1298 | 0, /* not on io commands */ | |
1299 | 100000, | |
1300 | NULL, | |
1301 | flags | SCSI_DATA_IN)); | |
15637ed4 | 1302 | } |
15637ed4 RG |
1303 | #ifdef __STDC__ |
1304 | #define b2tol(a) (((unsigned)(a##_1) << 8) + (unsigned)a##_0 ) | |
1305 | #else | |
1306 | #define b2tol(a) (((unsigned)(a/**/_1) << 8) + (unsigned)a/**/_0 ) | |
1307 | #endif | |
1308 | ||
519fb2b7 RG |
1309 | /* |
1310 | * Ask the drive what it's min and max blk sizes are. | |
1311 | */ | |
1312 | errval | |
15637ed4 | 1313 | st_rd_blk_lim(unit, flags) |
519fb2b7 | 1314 | u_int32 unit, flags; |
15637ed4 | 1315 | { |
519fb2b7 | 1316 | struct scsi_blk_limits scsi_cmd; |
15637ed4 | 1317 | struct scsi_blk_limits_data scsi_blkl; |
d4284689 | 1318 | struct st_data *st = st_data[unit]; |
519fb2b7 RG |
1319 | errval errno; |
1320 | struct scsi_link *sc_link = st->sc_link; | |
1321 | ||
1322 | /* | |
1323 | * First check if we have it all loaded | |
1324 | */ | |
1325 | if ((sc_link->flags & SDEV_MEDIA_LOADED)) | |
1326 | return 0; | |
1327 | ||
1328 | /* | |
1329 | * do a 'Read Block Limits' | |
1330 | */ | |
15637ed4 RG |
1331 | bzero(&scsi_cmd, sizeof(scsi_cmd)); |
1332 | scsi_cmd.op_code = READ_BLK_LIMITS; | |
1333 | ||
519fb2b7 RG |
1334 | /* |
1335 | * do the command, update the global values | |
1336 | */ | |
1337 | if (errno = scsi_scsi_cmd(sc_link, | |
1338 | (struct scsi_generic *) &scsi_cmd, | |
1339 | sizeof(scsi_cmd), | |
1340 | (u_char *) & scsi_blkl, | |
1341 | sizeof(scsi_blkl), | |
1342 | ST_RETRIES, | |
1343 | 5000, | |
1344 | NULL, | |
1345 | flags | SCSI_DATA_IN)) { | |
d4284689 | 1346 | return errno; |
519fb2b7 | 1347 | } |
15637ed4 RG |
1348 | st->blkmin = b2tol(scsi_blkl.min_length); |
1349 | st->blkmax = _3btol(&scsi_blkl.max_length_2); | |
1350 | ||
519fb2b7 RG |
1351 | SC_DEBUG(sc_link, SDEV_DB3, |
1352 | ("(%d <= blksiz <= %d)\n", st->blkmin, st->blkmax)); | |
d4284689 | 1353 | return 0; |
15637ed4 | 1354 | } |
a0becc21 | 1355 | |
519fb2b7 RG |
1356 | /* |
1357 | * Get the scsi driver to send a full inquiry to the | |
1358 | * device and use the results to fill out the global | |
1359 | * parameter structure. | |
1360 | * | |
1361 | * called from: | |
1362 | * attach | |
1363 | * open | |
1364 | * ioctl (to reset original blksize) | |
1365 | */ | |
1366 | errval | |
15637ed4 | 1367 | st_mode_sense(unit, flags) |
519fb2b7 | 1368 | u_int32 unit, flags; |
15637ed4 | 1369 | { |
519fb2b7 RG |
1370 | u_int32 scsi_sense_len; |
1371 | errval errno; | |
1372 | char *scsi_sense_ptr; | |
1373 | struct scsi_mode_sense scsi_cmd; | |
1374 | struct scsi_sense { | |
1375 | struct scsi_mode_header header; | |
1376 | struct blk_desc blk_desc; | |
1377 | } scsi_sense; | |
1378 | ||
1379 | struct scsi_sense_page_0 { | |
1380 | struct scsi_mode_header header; | |
1381 | struct blk_desc blk_desc; | |
1382 | unsigned char sense_data[PAGE_0_SENSE_DATA_SIZE]; | |
1383 | /* Tandberg tape drives returns page 00 | |
1384 | * with the sense data, whether or not | |
1385 | * you want it( ie the don't like you | |
1386 | * saying you want anything less!!!!! | |
1387 | * They also expect page 00 | |
1388 | * back when you issue a mode select | |
1389 | */ | |
1390 | } scsi_sense_page_0; | |
1391 | struct st_data *st = st_data[unit]; | |
1392 | struct scsi_link *sc_link = st->sc_link; | |
15637ed4 | 1393 | |
519fb2b7 RG |
1394 | /* |
1395 | * Define what sort of structure we're working with | |
1396 | */ | |
1397 | if (st->quirks & ST_Q_NEEDS_PAGE_0) { | |
a0becc21 NW |
1398 | scsi_sense_len = sizeof(scsi_sense_page_0); |
1399 | scsi_sense_ptr = (char *) &scsi_sense_page_0; | |
519fb2b7 | 1400 | } else { |
a0becc21 NW |
1401 | scsi_sense_len = sizeof(scsi_sense); |
1402 | scsi_sense_ptr = (char *) &scsi_sense; | |
1403 | } | |
519fb2b7 RG |
1404 | /* |
1405 | * Set up a mode sense | |
1406 | */ | |
15637ed4 RG |
1407 | bzero(&scsi_cmd, sizeof(scsi_cmd)); |
1408 | scsi_cmd.op_code = MODE_SENSE; | |
a0becc21 NW |
1409 | scsi_cmd.length = scsi_sense_len; |
1410 | ||
519fb2b7 RG |
1411 | /* |
1412 | * do the command, but we don't need the results | |
1413 | * just print them for our interest's sake, if asked, | |
1414 | * or if we need it as a template for the mode select | |
1415 | * store it away. | |
1416 | */ | |
1417 | if (errno = scsi_scsi_cmd(sc_link, | |
1418 | (struct scsi_generic *) &scsi_cmd, | |
1419 | sizeof(scsi_cmd), | |
1420 | (u_char *) scsi_sense_ptr, | |
1421 | scsi_sense_len, | |
1422 | ST_RETRIES, | |
1423 | 5000, | |
1424 | NULL, | |
1425 | flags | SCSI_DATA_IN)) { | |
d4284689 | 1426 | return errno; |
519fb2b7 RG |
1427 | } |
1428 | st->numblks = _3btol(((struct scsi_sense *)scsi_sense_ptr)->blk_desc.nblocks); | |
1429 | st->media_blksiz = _3btol(((struct scsi_sense *)scsi_sense_ptr)->blk_desc.blklen); | |
1430 | st->media_density = ((struct scsi_sense *) scsi_sense_ptr)->blk_desc.density; | |
1431 | if (((struct scsi_sense *) scsi_sense_ptr)->header.dev_spec & | |
1432 | SMH_DSP_WRITE_PROT) { | |
d4284689 | 1433 | st->flags |= ST_READONLY; |
15637ed4 | 1434 | } |
519fb2b7 RG |
1435 | SC_DEBUG(sc_link, SDEV_DB3, |
1436 | ("density code 0x%x, %d-byte blocks, write-%s, ", | |
1437 | st->media_density, st->media_blksiz, | |
1438 | st->flags & ST_READONLY ? "protected" : "enabled")); | |
1439 | SC_DEBUG(sc_link, SDEV_DB3, | |
1440 | ("%sbuffered\n", | |
1441 | ((struct scsi_sense *) scsi_sense_ptr)->header.dev_spec | |
1442 | & SMH_DSP_BUFF_MODE ? "" : "un")); | |
1443 | if (st->quirks & ST_Q_NEEDS_PAGE_0) { | |
1444 | bcopy(((struct scsi_sense_page_0 *) scsi_sense_ptr)->sense_data, | |
1445 | st->sense_data, | |
1446 | sizeof(((struct scsi_sense_page_0 *) scsi_sense_ptr)->sense_data)); | |
a0becc21 | 1447 | } |
519fb2b7 | 1448 | sc_link->flags |= SDEV_MEDIA_LOADED; |
d4284689 | 1449 | return 0; |
15637ed4 RG |
1450 | } |
1451 | ||
519fb2b7 RG |
1452 | /* |
1453 | * Send a filled out parameter structure to the drive to | |
1454 | * set it into the desire modes etc. | |
1455 | */ | |
1456 | errval | |
d4284689 | 1457 | st_mode_select(unit, flags) |
519fb2b7 | 1458 | u_int32 unit, flags; |
15637ed4 | 1459 | { |
519fb2b7 RG |
1460 | u_int32 dat_len; |
1461 | char *dat_ptr; | |
15637ed4 | 1462 | struct scsi_mode_select scsi_cmd; |
519fb2b7 RG |
1463 | struct dat { |
1464 | struct scsi_mode_header header; | |
1465 | struct blk_desc blk_desc; | |
1466 | } dat; | |
1467 | struct dat_page_0 { | |
1468 | struct scsi_mode_header header; | |
1469 | struct blk_desc blk_desc; | |
1470 | unsigned char sense_data[PAGE_0_SENSE_DATA_SIZE]; | |
1471 | } dat_page_0; | |
1472 | struct st_data *st = st_data[unit]; | |
1473 | ||
1474 | /* | |
1475 | * Define what sort of structure we're working with | |
1476 | */ | |
1477 | if (st->quirks & ST_Q_NEEDS_PAGE_0) { | |
a0becc21 NW |
1478 | dat_len = sizeof(dat_page_0); |
1479 | dat_ptr = (char *) &dat_page_0; | |
519fb2b7 | 1480 | } else { |
a0becc21 NW |
1481 | dat_len = sizeof(dat); |
1482 | dat_ptr = (char *) &dat; | |
1483 | } | |
519fb2b7 RG |
1484 | /* |
1485 | * Set up for a mode select | |
1486 | */ | |
a0becc21 | 1487 | bzero(dat_ptr, dat_len); |
15637ed4 RG |
1488 | bzero(&scsi_cmd, sizeof(scsi_cmd)); |
1489 | scsi_cmd.op_code = MODE_SELECT; | |
a0becc21 | 1490 | scsi_cmd.length = dat_len; |
519fb2b7 RG |
1491 | ((struct dat *) dat_ptr)->header.blk_desc_len = sizeof(struct blk_desc); |
1492 | ((struct dat *) dat_ptr)->header.dev_spec |= SMH_DSP_BUFF_MODE_ON; | |
1493 | ((struct dat *) dat_ptr)->blk_desc.density = st->density; | |
1494 | if (st->flags & ST_FIXEDBLOCKS) { | |
1495 | lto3b(st->blksiz, ((struct dat *) dat_ptr)->blk_desc.blklen); | |
a0becc21 | 1496 | } |
519fb2b7 RG |
1497 | if (st->quirks & ST_Q_NEEDS_PAGE_0) { |
1498 | bcopy(st->sense_data, ((struct dat_page_0 *) dat_ptr)->sense_data, | |
1499 | sizeof(((struct dat_page_0 *) dat_ptr)->sense_data)); | |
1500 | /* the Tandberg tapes need the block size to */ | |
1501 | /* be set on each mode sense/select. */ | |
15637ed4 | 1502 | } |
519fb2b7 RG |
1503 | /* |
1504 | * do the command | |
1505 | */ | |
1506 | return (scsi_scsi_cmd(st->sc_link, | |
1507 | (struct scsi_generic *) &scsi_cmd, | |
1508 | sizeof(scsi_cmd), | |
1509 | (u_char *) dat_ptr, | |
1510 | dat_len, | |
1511 | ST_RETRIES, | |
1512 | 5000, | |
1513 | NULL, | |
1514 | flags | SCSI_DATA_OUT)); | |
15637ed4 RG |
1515 | } |
1516 | ||
519fb2b7 RG |
1517 | /* |
1518 | * skip N blocks/filemarks/seq filemarks/eom | |
1519 | */ | |
1520 | errval | |
1521 | st_space(unit, number, what, flags) | |
1522 | u_int32 unit, what, flags; | |
1523 | int32 number; | |
15637ed4 | 1524 | { |
519fb2b7 | 1525 | errval error; |
15637ed4 | 1526 | struct scsi_space scsi_cmd; |
519fb2b7 | 1527 | struct st_data *st = st_data[unit]; |
15637ed4 | 1528 | |
fde1aeb2 | 1529 | switch ((int)what) { |
519fb2b7 RG |
1530 | case SP_BLKS: |
1531 | if (st->flags & ST_PER_ACTION) { | |
1532 | if (number > 0) { | |
fca1f689 | 1533 | st->flags &= ~ST_PER_ACTION; |
519fb2b7 RG |
1534 | return (EIO); |
1535 | } else if (number < 0) { | |
1536 | if (st->flags & ST_AT_FILEMARK) { | |
1537 | /* | |
1538 | * Handling of ST_AT_FILEMARK | |
1539 | * in st_space will fill in the | |
1540 | * right file mark count. | |
1541 | */ | |
fca1f689 RG |
1542 | error = st_space(unit, 0, SP_FILEMARKS, |
1543 | flags); | |
519fb2b7 RG |
1544 | if (error) |
1545 | return (error); | |
fca1f689 | 1546 | } |
519fb2b7 | 1547 | if (st->flags & ST_BLANK_READ) { |
fca1f689 | 1548 | st->flags &= ~ST_BLANK_READ; |
519fb2b7 | 1549 | return (EIO); |
fca1f689 RG |
1550 | } |
1551 | st->flags &= ~ST_EIO_PENDING; | |
1552 | } | |
1553 | } | |
1554 | break; | |
519fb2b7 RG |
1555 | case SP_FILEMARKS: |
1556 | if (st->flags & ST_EIO_PENDING) { | |
1557 | if (number > 0) { /* pretend we just discover the error */ | |
fca1f689 | 1558 | st->flags &= ~ST_EIO_PENDING; |
519fb2b7 RG |
1559 | return (EIO); |
1560 | } else if (number < 0) { /* back away from the error */ | |
fca1f689 | 1561 | st->flags &= ~ST_EIO_PENDING; |
519fb2b7 | 1562 | } |
fca1f689 | 1563 | } |
519fb2b7 | 1564 | if (st->flags & ST_AT_FILEMARK) { |
fca1f689 RG |
1565 | st->flags &= ~ST_AT_FILEMARK; |
1566 | number--; | |
1567 | } | |
519fb2b7 | 1568 | if ((st->flags & ST_BLANK_READ) && (number < 0)) { /* back away from unwritten tape */ |
fca1f689 | 1569 | st->flags &= ~ST_BLANK_READ; |
519fb2b7 | 1570 | number++; /* dubious */ |
fca1f689 RG |
1571 | } |
1572 | } | |
519fb2b7 RG |
1573 | if (number == 0) { |
1574 | return (ESUCCESS); | |
1575 | } | |
15637ed4 RG |
1576 | bzero(&scsi_cmd, sizeof(scsi_cmd)); |
1577 | scsi_cmd.op_code = SPACE; | |
869c4419 | 1578 | scsi_cmd.byte2 = what & SS_CODE; |
519fb2b7 RG |
1579 | lto3b(number, scsi_cmd.number); |
1580 | return (scsi_scsi_cmd(st->sc_link, | |
1581 | (struct scsi_generic *) &scsi_cmd, | |
1582 | sizeof(scsi_cmd), | |
1583 | 0, | |
1584 | 0, | |
1585 | 0, /* no retries please , just fail */ | |
1586 | 600000, /* 10 mins enough? */ | |
1587 | NULL, | |
1588 | flags)); | |
15637ed4 | 1589 | } |
519fb2b7 RG |
1590 | |
1591 | /* | |
1592 | * write N filemarks | |
1593 | */ | |
1594 | errval | |
1595 | st_write_filemarks(unit, number, flags) | |
1596 | u_int32 unit, flags; | |
1597 | int32 number; | |
15637ed4 RG |
1598 | { |
1599 | struct scsi_write_filemarks scsi_cmd; | |
519fb2b7 | 1600 | struct st_data *st = st_data[unit]; |
15637ed4 | 1601 | |
519fb2b7 RG |
1602 | /* |
1603 | * It's hard to write a negative number of file marks. | |
1604 | * Don't try. | |
1605 | */ | |
1606 | if (number < 0) { | |
1607 | return EINVAL; | |
1608 | } | |
fde1aeb2 | 1609 | switch ((int)number) { |
519fb2b7 | 1610 | case 0: /* really a command to sync the drive's buffers */ |
fca1f689 | 1611 | break; |
519fb2b7 RG |
1612 | case 1: |
1613 | if (st->flags & ST_FM_WRITTEN) { /* already have one down */ | |
fca1f689 | 1614 | st->flags &= ~ST_WRITTEN; |
519fb2b7 | 1615 | } else { |
fca1f689 | 1616 | st->flags |= ST_FM_WRITTEN; |
519fb2b7 | 1617 | } |
fca1f689 RG |
1618 | st->flags &= ~ST_PER_ACTION; |
1619 | break; | |
1620 | default: | |
1621 | st->flags &= ~(ST_PER_ACTION | ST_WRITTEN); | |
1622 | } | |
15637ed4 RG |
1623 | bzero(&scsi_cmd, sizeof(scsi_cmd)); |
1624 | scsi_cmd.op_code = WRITE_FILEMARKS; | |
519fb2b7 RG |
1625 | lto3b(number, scsi_cmd.number); |
1626 | return scsi_scsi_cmd(st->sc_link, | |
1627 | (struct scsi_generic *) &scsi_cmd, | |
1628 | sizeof(scsi_cmd), | |
1629 | 0, | |
1630 | 0, | |
1631 | 0, /* no retries, just fail */ | |
1632 | 100000, /* 10 secs.. (may need to repos head ) */ | |
1633 | NULL, | |
1634 | flags); | |
15637ed4 | 1635 | } |
fca1f689 | 1636 | |
519fb2b7 RG |
1637 | /* |
1638 | * Make sure the right number of file marks is on tape if the | |
1639 | * tape has been written. If the position argument is true, | |
1640 | * leave the tape positioned where it was originally. | |
1641 | * | |
1642 | * nmarks returns the number of marks to skip (or, if position | |
1643 | * true, which were skipped) to get back original position. | |
1644 | */ | |
1645 | int32 | |
fca1f689 | 1646 | st_chkeod(unit, position, nmarks, flags) |
519fb2b7 RG |
1647 | u_int32 unit; |
1648 | boolean position; | |
1649 | int32 *nmarks; | |
1650 | u_int32 flags; | |
fca1f689 | 1651 | { |
519fb2b7 RG |
1652 | errval error; |
1653 | struct st_data *st = st_data[unit]; | |
fca1f689 | 1654 | |
fde1aeb2 | 1655 | switch ((int)(st->flags & (ST_WRITTEN | ST_FM_WRITTEN | ST_2FM_AT_EOD))) { |
fca1f689 RG |
1656 | default: |
1657 | *nmarks = 0; | |
519fb2b7 RG |
1658 | return (ESUCCESS); |
1659 | case ST_WRITTEN: | |
1660 | case ST_WRITTEN | ST_FM_WRITTEN | ST_2FM_AT_EOD: | |
fca1f689 RG |
1661 | *nmarks = 1; |
1662 | break; | |
519fb2b7 | 1663 | case ST_WRITTEN | ST_2FM_AT_EOD: |
fca1f689 RG |
1664 | *nmarks = 2; |
1665 | } | |
1666 | error = st_write_filemarks(unit, *nmarks, flags); | |
519fb2b7 | 1667 | if (position && (error == ESUCCESS)) |
fca1f689 RG |
1668 | error = st_space(unit, -*nmarks, SP_FILEMARKS, flags); |
1669 | return (error); | |
1670 | } | |
1671 | ||
519fb2b7 RG |
1672 | /* |
1673 | * load/unload (with retension if true) | |
1674 | */ | |
1675 | errval | |
1676 | st_load(unit, type, flags) | |
1677 | u_int32 unit, type, flags; | |
15637ed4 | 1678 | { |
519fb2b7 RG |
1679 | struct scsi_load scsi_cmd; |
1680 | struct st_data *st = st_data[unit]; | |
1681 | struct scsi_link *sc_link = st->sc_link; | |
15637ed4 | 1682 | |
15637ed4 | 1683 | bzero(&scsi_cmd, sizeof(scsi_cmd)); |
519fb2b7 RG |
1684 | if (type != LD_LOAD) { |
1685 | errval error; | |
1686 | int32 nmarks; | |
fca1f689 RG |
1687 | |
1688 | error = st_chkeod(unit, FALSE, &nmarks, flags); | |
519fb2b7 RG |
1689 | if (error != ESUCCESS) |
1690 | return (error); | |
1691 | sc_link->flags &= ~SDEV_MEDIA_LOADED; | |
fca1f689 | 1692 | } |
519fb2b7 RG |
1693 | if (st->quirks & ST_Q_IGNORE_LOADS) |
1694 | return (0); | |
fca1f689 RG |
1695 | scsi_cmd.op_code = LOAD_UNLOAD; |
1696 | scsi_cmd.how |= type; | |
519fb2b7 RG |
1697 | return (scsi_scsi_cmd(st->sc_link, |
1698 | (struct scsi_generic *) &scsi_cmd, | |
1699 | sizeof(scsi_cmd), | |
1700 | 0, | |
1701 | 0, | |
1702 | ST_RETRIES, | |
1703 | 300000, /* 5 min */ | |
1704 | NULL, | |
1705 | flags)); | |
15637ed4 | 1706 | } |
fca1f689 | 1707 | |
519fb2b7 RG |
1708 | /* |
1709 | * Rewind the device | |
1710 | */ | |
1711 | errval | |
1712 | st_rewind(unit, immed, flags) | |
1713 | u_int32 unit, flags; | |
1714 | boolean immed; | |
15637ed4 | 1715 | { |
519fb2b7 RG |
1716 | struct scsi_rewind scsi_cmd; |
1717 | struct st_data *st = st_data[unit]; | |
1718 | errval error; | |
1719 | int32 nmarks; | |
15637ed4 | 1720 | |
fca1f689 | 1721 | error = st_chkeod(unit, FALSE, &nmarks, flags); |
519fb2b7 RG |
1722 | if (error != ESUCCESS) |
1723 | return (error); | |
d4284689 | 1724 | st->flags &= ~ST_PER_ACTION; |
15637ed4 RG |
1725 | bzero(&scsi_cmd, sizeof(scsi_cmd)); |
1726 | scsi_cmd.op_code = REWIND; | |
d4284689 | 1727 | scsi_cmd.byte2 = immed ? SR_IMMED : 0; |
519fb2b7 RG |
1728 | return (scsi_scsi_cmd(st->sc_link, |
1729 | (struct scsi_generic *) &scsi_cmd, | |
1730 | sizeof(scsi_cmd), | |
1731 | 0, | |
1732 | 0, | |
1733 | ST_RETRIES, | |
1734 | immed ? 5000 : 300000, /* 5 sec or 5 min */ | |
1735 | NULL, | |
1736 | flags)); | |
d4284689 RG |
1737 | } |
1738 | ||
519fb2b7 RG |
1739 | #ifdef NETBSD |
1740 | #define SIGNAL_SHORT_READ | |
d4284689 | 1741 | #else |
519fb2b7 RG |
1742 | #define SIGNAL_SHORT_READ bp->b_flags |= B_ERROR; |
1743 | #endif | |
d4284689 | 1744 | |
519fb2b7 RG |
1745 | /* |
1746 | * Look at the returned sense and act on the error and detirmine | |
1747 | * The unix error number to pass back... (0 = report no error) | |
1748 | * (-1 = continue processing) | |
1749 | */ | |
1750 | errval | |
1751 | st_interpret_sense(xs) | |
1752 | struct scsi_xfer *xs; | |
d4284689 | 1753 | { |
519fb2b7 RG |
1754 | struct scsi_link *sc_link = xs->sc_link; |
1755 | struct scsi_sense_data *sense = &(xs->sense); | |
1756 | boolean silent = xs->flags & SCSI_SILENT; | |
1757 | struct buf *bp = xs->bp; | |
1758 | u_int32 unit = sc_link->dev_unit; | |
1759 | struct st_data *st = st_data[unit]; | |
1760 | u_int32 key; | |
1761 | int32 info; | |
1762 | ||
1763 | /* | |
1764 | * Get the sense fields and work out what code | |
1765 | */ | |
1766 | if (sense->error_code & SSD_ERRCODE_VALID) { | |
1767 | info = ntohl(*((int32 *) sense->ext.extended.info)); | |
1768 | } else { | |
1769 | info = xs->datalen; /* bad choice if fixed blocks */ | |
d4284689 | 1770 | } |
519fb2b7 RG |
1771 | if ((sense->error_code & SSD_ERRCODE) != 0x70) { |
1772 | return (-1); /* let the generic code handle it */ | |
d4284689 | 1773 | } |
519fb2b7 RG |
1774 | if (st->flags & ST_FIXEDBLOCKS) { |
1775 | xs->resid = info * st->blksiz; | |
1776 | if (sense->ext.extended.flags & SSD_EOM) { | |
1777 | st->flags |= ST_EIO_PENDING; | |
1778 | if (bp) { | |
1779 | bp->b_resid = xs->resid; | |
1780 | SIGNAL_SHORT_READ | |
d4284689 | 1781 | } |
15637ed4 | 1782 | } |
519fb2b7 RG |
1783 | if (sense->ext.extended.flags & SSD_FILEMARK) { |
1784 | st->flags |= ST_AT_FILEMARK; | |
1785 | if (bp) { | |
1786 | bp->b_resid = xs->resid; | |
1787 | SIGNAL_SHORT_READ | |
1788 | } | |
15637ed4 | 1789 | } |
519fb2b7 RG |
1790 | if (sense->ext.extended.flags & SSD_ILI) { |
1791 | st->flags |= ST_EIO_PENDING; | |
1792 | if (bp) { | |
1793 | bp->b_resid = xs->resid; | |
1794 | SIGNAL_SHORT_READ | |
d4284689 | 1795 | } |
519fb2b7 RG |
1796 | if (sense->error_code & SSD_ERRCODE_VALID && |
1797 | !silent) | |
1798 | printf("st%d: block wrong size" | |
1799 | ", %d blocks residual\n", unit | |
1800 | ,info); | |
1801 | ||
1802 | /* | |
1803 | * This quirk code helps the drive read | |
1804 | * the first tape block, regardless of | |
1805 | * format. That is required for these | |
1806 | * drives to return proper MODE SENSE | |
1807 | * information. | |
1808 | */ | |
1809 | if ((st->quirks & ST_Q_SNS_HLP) && | |
1810 | !(sc_link->flags & SDEV_MEDIA_LOADED)) { | |
1811 | st->blksiz -= 512; | |
d4284689 | 1812 | } |
519fb2b7 RG |
1813 | } |
1814 | /* | |
1815 | * If no data was tranfered, do it immediatly | |
1816 | */ | |
1817 | if (xs->resid >= xs->datalen) { | |
1818 | if (st->flags & ST_EIO_PENDING) { | |
1819 | return EIO; | |
d4284689 | 1820 | } |
519fb2b7 RG |
1821 | if (st->flags & ST_AT_FILEMARK) { |
1822 | if (bp) { | |
1823 | bp->b_resid = xs->resid; | |
1824 | SIGNAL_SHORT_READ | |
d4284689 | 1825 | } |
519fb2b7 | 1826 | return 0; |
d4284689 | 1827 | } |
15637ed4 | 1828 | } |
519fb2b7 RG |
1829 | } else { /* must be variable mode */ |
1830 | xs->resid = xs->datalen; /* to be sure */ | |
1831 | if (sense->ext.extended.flags & SSD_EOM) { | |
1832 | return (EIO); | |
1833 | } | |
1834 | if (sense->ext.extended.flags & SSD_FILEMARK) { | |
1835 | if (bp) | |
1836 | bp->b_resid = bp->b_bcount; | |
1837 | return 0; | |
1838 | } | |
1839 | if (sense->ext.extended.flags & SSD_ILI) { | |
1840 | if (info < 0) { | |
1841 | /* | |
1842 | * the record was bigger than the read | |
1843 | */ | |
1844 | if (!silent) | |
1845 | printf("st%d: %d-byte record " | |
1846 | "too big\n", unit, | |
1847 | xs->datalen - info); | |
1848 | return (EIO); | |
15637ed4 | 1849 | } |
519fb2b7 RG |
1850 | xs->resid = info; |
1851 | if (bp) { | |
1852 | bp->b_resid = info; | |
1853 | SIGNAL_SHORT_READ | |
d4284689 | 1854 | } |
519fb2b7 RG |
1855 | } |
1856 | } | |
1857 | key = sense->ext.extended.flags & SSD_KEY; | |
1858 | ||
1859 | if (key == 0x8) { | |
1860 | /* | |
1861 | * This quirk code helps the drive read the | |
1862 | * first tape block, regardless of format. That | |
1863 | * is required for these drives to return proper | |
1864 | * MODE SENSE information. | |
1865 | */ | |
1866 | if ((st->quirks & ST_Q_SNS_HLP) && | |
1867 | !(sc_link->flags & SDEV_MEDIA_LOADED)) { /* still starting */ | |
1868 | st->blksiz -= 512; | |
1869 | } else if (!(st->flags & (ST_2FM_AT_EOD | ST_BLANK_READ))) { | |
1870 | st->flags |= ST_BLANK_READ; | |
1871 | xs->resid = xs->datalen; | |
1872 | if (bp) { | |
1873 | bp->b_resid = xs->resid; | |
1874 | /*return an EOF */ | |
15637ed4 | 1875 | } |
519fb2b7 RG |
1876 | return (ESUCCESS); |
1877 | } | |
1878 | } | |
1879 | return (-1); /* let the default/generic handler handle it */ | |
1880 | } | |
15637ed4 | 1881 | |
519fb2b7 RG |
1882 | /* |
1883 | * The quirk here is that the drive returns some value to st_mode_sense | |
1884 | * incorrectly until the tape has actually passed by the head. | |
1885 | * | |
1886 | * The method is to set the drive to large fixed-block state (user-specified | |
1887 | * density and 1024-byte blocks), then read and rewind to get it to sense the | |
1888 | * tape. If that doesn't work, try 512-byte fixed blocks. If that doesn't | |
1889 | * work, as a last resort, try variable- length blocks. The result will be | |
1890 | * the ability to do an accurate st_mode_sense. | |
1891 | * | |
1892 | * We know we can do a rewind because we just did a load, which implies rewind. | |
1893 | * Rewind seems preferable to space backward if we have a virgin tape. | |
1894 | * | |
1895 | * The rest of the code for this quirk is in ILI processing and BLANK CHECK | |
1896 | * error processing, both part of st_interpret_sense. | |
1897 | */ | |
1898 | errval | |
1899 | st_touch_tape(unit) | |
1900 | u_int32 unit; | |
1901 | { | |
1902 | struct st_data *st = st_data[unit]; | |
1903 | char *buf; | |
1904 | u_int32 readsiz; | |
1905 | errval errno; | |
0269d546 | 1906 | |
519fb2b7 RG |
1907 | buf = malloc(1024, M_TEMP, M_NOWAIT); |
1908 | if (!buf) | |
1909 | return (ENOMEM); | |
0269d546 | 1910 | |
519fb2b7 RG |
1911 | if (errno = st_mode_sense(unit, 0)) { |
1912 | goto bad; | |
1913 | } | |
1914 | st->blksiz = 1024; | |
1915 | do { | |
fde1aeb2 | 1916 | switch ((int)st->blksiz) { |
519fb2b7 RG |
1917 | case 512: |
1918 | case 1024: | |
1919 | readsiz = st->blksiz; | |
1920 | st->flags |= ST_FIXEDBLOCKS; | |
1921 | break; | |
0269d546 | 1922 | default: |
519fb2b7 RG |
1923 | readsiz = 1; |
1924 | st->flags &= ~ST_FIXEDBLOCKS; | |
1925 | } if (errno = st_mode_select(unit, 0)) { | |
1926 | goto bad; | |
15637ed4 | 1927 | } |
519fb2b7 RG |
1928 | st_read(unit, buf, readsiz, SCSI_SILENT); |
1929 | if (errno = st_rewind(unit, FALSE, 0)) { | |
1930 | bad: free(buf, M_TEMP); | |
1931 | return (errno); | |
15637ed4 | 1932 | } |
519fb2b7 RG |
1933 | } while (readsiz != 1 && readsiz > st->blksiz); |
1934 | free(buf, M_TEMP); | |
1935 | return 0; | |
15637ed4 | 1936 | } |