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 | */ | |
fde1aeb2 | 24 | /* $Revision: 1.13 $ */ |
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 | * |
fde1aeb2 | 30 | * $Id: st.c,v 1.13 1993/11/18 05:03:05 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) { | |
488 | return (ENXIO); | |
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 | |
519fb2b7 RG |
914 | /* |
915 | * Place it in the queue of activities for this tape | |
916 | * at the end (a bit silly because we only have on user.. | |
917 | * (but it could fork() )) | |
918 | */ | |
d4284689 | 919 | dp = &(st->buf_queue); |
519fb2b7 | 920 | while (*dp) { |
d4284689 | 921 | dp = &((*dp)->b_actf); |
519fb2b7 | 922 | } |
d4284689 | 923 | *dp = bp; |
2aecffae | 924 | bp->b_actf = NULL; |
15637ed4 | 925 | |
519fb2b7 RG |
926 | /* |
927 | * Tell the device to get going on the transfer if it's | |
928 | * not doing anything, otherwise just wait for completion | |
929 | * (All a bit silly if we're only allowing 1 open but..) | |
930 | */ | |
15637ed4 RG |
931 | ststart(unit); |
932 | ||
933 | splx(opri); | |
934 | return; | |
935 | bad: | |
936 | bp->b_flags |= B_ERROR; | |
937 | done: | |
519fb2b7 RG |
938 | /* |
939 | * Correctly set the buf to indicate a completed xfer | |
940 | */ | |
15637ed4 RG |
941 | iodone(bp); |
942 | return; | |
943 | } | |
944 | ||
519fb2b7 RG |
945 | /* |
946 | * ststart looks to see if there is a buf waiting for the device | |
947 | * and that the device is not already busy. If both are true, | |
948 | * It dequeues the buf and creates a scsi command to perform the | |
949 | * transfer required. The transfer request will call scsi_done | |
950 | * on completion, which will in turn call this routine again | |
951 | * so that the next queued transfer is performed. | |
952 | * The bufs are queued by the strategy routine (ststrategy) | |
953 | * | |
954 | * This routine is also called after other non-queued requests | |
955 | * have been made of the scsi driver, to ensure that the queue | |
956 | * continues to be drained. | |
957 | * ststart() is called at splbio | |
958 | */ | |
959 | void | |
960 | ststart(unit) | |
961 | u_int32 unit; | |
962 | { | |
963 | struct st_data *st = st_data[unit]; | |
964 | struct scsi_link *sc_link = st->sc_link; | |
965 | register struct buf *bp = 0; | |
966 | struct scsi_rw_tape cmd; | |
967 | u_int32 flags; | |
968 | ||
969 | SC_DEBUG(sc_link, SDEV_DB2, ("ststart ")); | |
970 | /* | |
971 | * See if there is a buf to do and we are not already | |
972 | * doing one | |
973 | */ | |
974 | while (sc_link->opennings != 0) { | |
975 | ||
976 | /* if a special awaits, let it proceed first */ | |
977 | if (sc_link->flags & SDEV_WAITING) { | |
978 | wakeup((caddr_t)sc_link); | |
979 | return; | |
980 | } | |
981 | if ((bp = st->buf_queue) == NULL) { | |
982 | return; /* no work to bother with */ | |
983 | } | |
984 | st->buf_queue = bp->b_actf; | |
985 | ||
986 | /* | |
987 | * if the device has been unmounted byt the user | |
988 | * then throw away all requests until done | |
989 | */ | |
990 | if ((!(st->flags & ST_MOUNTED)) | |
991 | || (!(sc_link->flags & SDEV_MEDIA_LOADED))) { | |
992 | /* make sure that one implies the other.. */ | |
993 | sc_link->flags &= ~SDEV_MEDIA_LOADED; | |
994 | goto badnews; | |
995 | } | |
996 | /* | |
997 | * only FIXEDBLOCK devices have pending operations | |
998 | */ | |
999 | if (st->flags & ST_FIXEDBLOCKS) { | |
1000 | /* | |
1001 | * If we are at a filemark but have not reported it yet | |
1002 | * then we should report it now | |
1003 | */ | |
1004 | if (st->flags & ST_AT_FILEMARK) { | |
1005 | if ((bp->b_flags & B_READ) == B_WRITE) { | |
1006 | /* | |
1007 | * Handling of ST_AT_FILEMARK in | |
1008 | * st_space will fill in the right file | |
1009 | * mark count. | |
1010 | * Back up over filemark | |
1011 | */ | |
1012 | if (st_space(unit, 0, SP_FILEMARKS, 0) != | |
1013 | ESUCCESS) | |
1014 | goto badnews; | |
1015 | } else { | |
1016 | bp->b_resid = bp->b_bcount; | |
1017 | bp->b_error = 0; | |
1018 | bp->b_flags &= ~B_ERROR; | |
1019 | st->flags &= ~ST_AT_FILEMARK; | |
1020 | biodone(bp); | |
1021 | continue; /* seek more work */ | |
1022 | } | |
1023 | } | |
1024 | /* | |
1025 | * If we are at EIO (e.g. EOM) but have not reported it | |
1026 | * yet then we should report it now | |
1027 | */ | |
1028 | if (st->flags & ST_EIO_PENDING) { | |
1029 | bp->b_resid = bp->b_bcount; | |
1030 | bp->b_error = EIO; | |
1031 | bp->b_flags |= B_ERROR; | |
1032 | st->flags &= ~ST_EIO_PENDING; | |
1033 | biodone(bp); | |
1034 | continue; /* seek more work */ | |
1035 | } | |
1036 | } | |
1037 | /* | |
1038 | * Fill out the scsi command | |
1039 | */ | |
1040 | bzero(&cmd, sizeof(cmd)); | |
1041 | if ((bp->b_flags & B_READ) == B_WRITE) { | |
1042 | cmd.op_code = WRITE_COMMAND_TAPE; | |
1043 | st->flags &= ~ST_FM_WRITTEN; | |
1044 | st->flags |= ST_WRITTEN; | |
1045 | flags = SCSI_DATA_OUT; | |
1046 | } else { | |
1047 | cmd.op_code = READ_COMMAND_TAPE; | |
1048 | flags = SCSI_DATA_IN; | |
1049 | } | |
1050 | /* | |
1051 | * Handle "fixed-block-mode" tape drives by using the | |
1052 | * block count instead of the length. | |
1053 | */ | |
1054 | if (st->flags & ST_FIXEDBLOCKS) { | |
1055 | cmd.byte2 |= SRWT_FIXED; | |
1056 | lto3b(bp->b_bcount / st->blksiz, cmd.len); | |
1057 | } else { | |
1058 | lto3b(bp->b_bcount, cmd.len); | |
1059 | } | |
1060 | /* | |
1061 | * go ask the adapter to do all this for us | |
1062 | */ | |
1063 | if (scsi_scsi_cmd(sc_link, | |
1064 | (struct scsi_generic *) &cmd, | |
1065 | sizeof(cmd), | |
1066 | (u_char *) bp->b_un.b_addr, | |
1067 | bp->b_bcount, | |
1068 | 0, /* can't retry a read on a tape really */ | |
1069 | 100000, | |
1070 | bp, | |
1071 | flags | SCSI_NOSLEEP) == SUCCESSFULLY_QUEUED) { | |
1072 | stqueues++; | |
1073 | } else { | |
1074 | badnews: | |
1075 | printf("st%d: oops not queued\n", unit); | |
1076 | bp->b_flags |= B_ERROR; | |
1077 | bp->b_error = EIO; | |
1078 | biodone(bp); | |
1079 | } | |
1080 | } /* go back and see if we can cram more work in.. */ | |
1081 | } | |
15637ed4 | 1082 | |
519fb2b7 RG |
1083 | /* |
1084 | * Perform special action on behalf of the user; | |
1085 | * knows about the internals of this device | |
1086 | */ | |
1087 | errval | |
1088 | stioctl(dev, cmd, arg, flag) | |
1089 | dev_t dev; | |
1090 | int cmd; | |
1091 | caddr_t arg; | |
1092 | int flag; | |
d4284689 | 1093 | { |
519fb2b7 | 1094 | errval errcode = 0; |
d4284689 | 1095 | unsigned char unit; |
519fb2b7 RG |
1096 | u_int32 number, flags, dsty; |
1097 | struct st_data *st; | |
1098 | u_int32 hold_blksiz; | |
1099 | u_int32 hold_density; | |
1100 | int32 nmarks; | |
1101 | struct mtop *mt = (struct mtop *) arg; | |
1102 | ||
1103 | /* | |
1104 | * Find the device that the user is talking about | |
1105 | */ | |
1106 | flags = 0; /* give error messages, act on errors etc. */ | |
15637ed4 | 1107 | unit = UNIT(dev); |
0269d546 | 1108 | dsty = DSTY(dev); |
519fb2b7 RG |
1109 | st = st_data[unit]; |
1110 | hold_blksiz = st->blksiz; | |
1111 | hold_density = st->density; | |
15637ed4 | 1112 | |
519fb2b7 | 1113 | switch (cmd) { |
15637ed4 RG |
1114 | |
1115 | case MTIOCGET: | |
519fb2b7 RG |
1116 | { |
1117 | struct mtget *g = (struct mtget *) arg; | |
1118 | ||
1119 | SC_DEBUG(st->sc_link, SDEV_DB1, ("[ioctl: get status]\n")); | |
1120 | bzero(g, sizeof(struct mtget)); | |
1121 | g->mt_type = 0x7; /* Ultrix compat *//*? */ | |
1122 | g->mt_density = st->density; | |
1123 | g->mt_blksiz = st->blksiz; | |
1124 | g->mt_density0 = st->modes[0].density; | |
1125 | g->mt_density1 = st->modes[1].density; | |
1126 | g->mt_density2 = st->modes[2].density; | |
1127 | g->mt_density3 = st->modes[3].density; | |
1128 | g->mt_blksiz0 = st->modes[0].blksiz; | |
1129 | g->mt_blksiz1 = st->modes[1].blksiz; | |
1130 | g->mt_blksiz2 = st->modes[2].blksiz; | |
1131 | g->mt_blksiz3 = st->modes[3].blksiz; | |
1132 | break; | |
1133 | } | |
15637ed4 | 1134 | case MTIOCTOP: |
519fb2b7 | 1135 | { |
15637ed4 | 1136 | |
519fb2b7 RG |
1137 | SC_DEBUG(st->sc_link, SDEV_DB1, ("[ioctl: op=0x%x count=0x%x]\n", |
1138 | mt->mt_op, mt->mt_count)); | |
15637ed4 | 1139 | |
519fb2b7 RG |
1140 | /* compat: in U*x it is a short */ |
1141 | number = mt->mt_count; | |
1142 | switch ((short) (mt->mt_op)) { | |
1143 | case MTWEOF: /* write an end-of-file record */ | |
1144 | errcode = st_write_filemarks(unit, number, flags); | |
d4284689 | 1145 | break; |
519fb2b7 RG |
1146 | case MTBSF: /* backward space file */ |
1147 | number = -number; | |
1148 | case MTFSF: /* forward space file */ | |
1149 | errcode = st_chkeod(unit, FALSE, &nmarks, flags); | |
1150 | if (errcode == ESUCCESS) | |
1151 | errcode = st_space(unit, number - nmarks, | |
1152 | SP_FILEMARKS, flags); | |
1153 | break; | |
1154 | case MTBSR: /* backward space record */ | |
1155 | number = -number; | |
1156 | case MTFSR: /* forward space record */ | |
1157 | errcode = st_chkeod(unit, TRUE, &nmarks, flags); | |
1158 | if (errcode == ESUCCESS) | |
1159 | errcode = st_space(unit, number, SP_BLKS, flags); | |
1160 | break; | |
1161 | case MTREW: /* rewind */ | |
1162 | errcode = st_rewind(unit, FALSE, flags); | |
1163 | break; | |
1164 | case MTOFFL: /* rewind and put the drive offline */ | |
1165 | st_unmount(unit, EJECT); | |
1166 | break; | |
1167 | case MTNOP: /* no operation, sets status only */ | |
1168 | case MTCACHE: /* enable controller cache */ | |
1169 | case MTNOCACHE: /* disable controller cache */ | |
1170 | break; | |
1171 | case MTSETBSIZ: /* Set block size for device */ | |
1172 | #ifdef NOTYET | |
1173 | if (!(st->flags & ST_NEW_MOUNT)) { | |
1174 | uprintf("re-mount tape before changing blocksize"); | |
0269d546 RG |
1175 | errcode = EINVAL; |
1176 | break; | |
1177 | } | |
519fb2b7 RG |
1178 | #endif |
1179 | if (number == 0) { | |
1180 | st->flags &= ~ST_FIXEDBLOCKS; | |
1181 | } else { | |
1182 | if ((st->blkmin || st->blkmax) /* they exist */ | |
1183 | &&((number < st->blkmin | |
1184 | || number > st->blkmax))) { | |
1185 | errcode = EINVAL; | |
1186 | break; | |
1187 | } | |
1188 | st->flags |= ST_FIXEDBLOCKS; | |
1189 | } | |
1190 | st->blksiz = number; | |
1191 | st->flags |= ST_BLOCK_SET; /*XXX */ | |
1192 | goto try_new_value; | |
a0becc21 | 1193 | |
519fb2b7 RG |
1194 | case MTSETDNSTY: /* Set density for device and mode */ |
1195 | if (number > SCSI_2_MAX_DENSITY_CODE) { | |
1196 | errcode = EINVAL; | |
1197 | } else { | |
1198 | st->density = number; | |
1199 | } | |
1200 | goto try_new_value; | |
a0becc21 | 1201 | |
519fb2b7 | 1202 | default: |
869c4419 | 1203 | errcode = EINVAL; |
a0becc21 | 1204 | } |
a0becc21 | 1205 | break; |
15637ed4 | 1206 | } |
15637ed4 RG |
1207 | case MTIOCIEOT: |
1208 | case MTIOCEEOT: | |
15637ed4 | 1209 | break; |
869c4419 | 1210 | default: |
519fb2b7 RG |
1211 | if(MODE(dev) == CTLMODE) |
1212 | errcode = scsi_do_ioctl(st->sc_link,cmd,arg,flag); | |
1213 | else | |
1214 | errcode = ENOTTY; | |
1215 | break; | |
15637ed4 | 1216 | } |
869c4419 | 1217 | return errcode; |
519fb2b7 RG |
1218 | /*-----------------------------*/ |
1219 | try_new_value: | |
1220 | /* | |
1221 | * Check that the mode being asked for is aggreeable to the | |
1222 | * drive. If not, put it back the way it was. | |
1223 | */ | |
1224 | if (errcode = st_mode_select(unit, 0)) { /* put it back as it was */ | |
1225 | printf("st%d: Cannot set selected mode", unit); | |
1226 | st->density = hold_density; | |
1227 | st->blksiz = hold_blksiz; | |
1228 | if (st->blksiz) { | |
1229 | st->flags |= ST_FIXEDBLOCKS; | |
1230 | } else { | |
1231 | st->flags &= ~ST_FIXEDBLOCKS; | |
1232 | } | |
1233 | return (errcode); | |
1234 | } | |
1235 | /* | |
1236 | * As the drive liked it, if we are setting a new default, | |
1237 | * set it into the structures as such. | |
1238 | * | |
1239 | * The means for deciding this are not finalised yet | |
1240 | */ | |
1241 | if (MODE(dev) == 0x03) { | |
1242 | /* special mode */ | |
1243 | /* XXX */ | |
1244 | switch ((short) (mt->mt_op)) { | |
1245 | case MTSETBSIZ: | |
1246 | st->modes[dsty].blksiz = st->blksiz; | |
1247 | st->modeflags[dsty] |= BLKSIZE_SET_BY_USER; | |
1248 | break; | |
1249 | case MTSETDNSTY: | |
1250 | st->modes[dsty].density = st->density; | |
1251 | st->modeflags[dsty] |= DENSITY_SET_BY_USER; | |
1252 | break; | |
1253 | } | |
1254 | } | |
1255 | return 0; | |
15637ed4 RG |
1256 | } |
1257 | ||
519fb2b7 RG |
1258 | /* |
1259 | * Do a synchronous read. | |
1260 | */ | |
1261 | errval | |
1262 | st_read(unit, buf, size, flags) | |
1263 | u_int32 unit, size, flags; | |
1264 | char *buf; | |
15637ed4 | 1265 | { |
d4284689 RG |
1266 | struct scsi_rw_tape scsi_cmd; |
1267 | struct st_data *st = st_data[unit]; | |
15637ed4 | 1268 | |
519fb2b7 RG |
1269 | /* |
1270 | * If it's a null transfer, return immediatly | |
1271 | */ | |
1272 | if (size == 0) { | |
1273 | return (ESUCCESS); | |
d4284689 | 1274 | } |
d4284689 RG |
1275 | bzero(&scsi_cmd, sizeof(scsi_cmd)); |
1276 | scsi_cmd.op_code = READ_COMMAND_TAPE; | |
519fb2b7 RG |
1277 | if (st->flags & ST_FIXEDBLOCKS) { |
1278 | scsi_cmd.byte2 |= SRWT_FIXED; | |
1279 | lto3b(size / (st->blksiz ? st->blksiz : DEF_FIXED_BSIZE), | |
1280 | scsi_cmd.len); | |
1281 | } else { | |
1282 | lto3b(size, scsi_cmd.len); | |
1283 | } | |
1284 | return (scsi_scsi_cmd(st->sc_link, | |
1285 | (struct scsi_generic *) &scsi_cmd, | |
1286 | sizeof(scsi_cmd), | |
1287 | (u_char *) buf, | |
1288 | size, | |
1289 | 0, /* not on io commands */ | |
1290 | 100000, | |
1291 | NULL, | |
1292 | flags | SCSI_DATA_IN)); | |
15637ed4 | 1293 | } |
15637ed4 RG |
1294 | #ifdef __STDC__ |
1295 | #define b2tol(a) (((unsigned)(a##_1) << 8) + (unsigned)a##_0 ) | |
1296 | #else | |
1297 | #define b2tol(a) (((unsigned)(a/**/_1) << 8) + (unsigned)a/**/_0 ) | |
1298 | #endif | |
1299 | ||
519fb2b7 RG |
1300 | /* |
1301 | * Ask the drive what it's min and max blk sizes are. | |
1302 | */ | |
1303 | errval | |
15637ed4 | 1304 | st_rd_blk_lim(unit, flags) |
519fb2b7 | 1305 | u_int32 unit, flags; |
15637ed4 | 1306 | { |
519fb2b7 | 1307 | struct scsi_blk_limits scsi_cmd; |
15637ed4 | 1308 | struct scsi_blk_limits_data scsi_blkl; |
d4284689 | 1309 | struct st_data *st = st_data[unit]; |
519fb2b7 RG |
1310 | errval errno; |
1311 | struct scsi_link *sc_link = st->sc_link; | |
1312 | ||
1313 | /* | |
1314 | * First check if we have it all loaded | |
1315 | */ | |
1316 | if ((sc_link->flags & SDEV_MEDIA_LOADED)) | |
1317 | return 0; | |
1318 | ||
1319 | /* | |
1320 | * do a 'Read Block Limits' | |
1321 | */ | |
15637ed4 RG |
1322 | bzero(&scsi_cmd, sizeof(scsi_cmd)); |
1323 | scsi_cmd.op_code = READ_BLK_LIMITS; | |
1324 | ||
519fb2b7 RG |
1325 | /* |
1326 | * do the command, update the global values | |
1327 | */ | |
1328 | if (errno = scsi_scsi_cmd(sc_link, | |
1329 | (struct scsi_generic *) &scsi_cmd, | |
1330 | sizeof(scsi_cmd), | |
1331 | (u_char *) & scsi_blkl, | |
1332 | sizeof(scsi_blkl), | |
1333 | ST_RETRIES, | |
1334 | 5000, | |
1335 | NULL, | |
1336 | flags | SCSI_DATA_IN)) { | |
d4284689 | 1337 | return errno; |
519fb2b7 | 1338 | } |
15637ed4 RG |
1339 | st->blkmin = b2tol(scsi_blkl.min_length); |
1340 | st->blkmax = _3btol(&scsi_blkl.max_length_2); | |
1341 | ||
519fb2b7 RG |
1342 | SC_DEBUG(sc_link, SDEV_DB3, |
1343 | ("(%d <= blksiz <= %d)\n", st->blkmin, st->blkmax)); | |
d4284689 | 1344 | return 0; |
15637ed4 | 1345 | } |
a0becc21 | 1346 | |
519fb2b7 RG |
1347 | /* |
1348 | * Get the scsi driver to send a full inquiry to the | |
1349 | * device and use the results to fill out the global | |
1350 | * parameter structure. | |
1351 | * | |
1352 | * called from: | |
1353 | * attach | |
1354 | * open | |
1355 | * ioctl (to reset original blksize) | |
1356 | */ | |
1357 | errval | |
15637ed4 | 1358 | st_mode_sense(unit, flags) |
519fb2b7 | 1359 | u_int32 unit, flags; |
15637ed4 | 1360 | { |
519fb2b7 RG |
1361 | u_int32 scsi_sense_len; |
1362 | errval errno; | |
1363 | char *scsi_sense_ptr; | |
1364 | struct scsi_mode_sense scsi_cmd; | |
1365 | struct scsi_sense { | |
1366 | struct scsi_mode_header header; | |
1367 | struct blk_desc blk_desc; | |
1368 | } scsi_sense; | |
1369 | ||
1370 | struct scsi_sense_page_0 { | |
1371 | struct scsi_mode_header header; | |
1372 | struct blk_desc blk_desc; | |
1373 | unsigned char sense_data[PAGE_0_SENSE_DATA_SIZE]; | |
1374 | /* Tandberg tape drives returns page 00 | |
1375 | * with the sense data, whether or not | |
1376 | * you want it( ie the don't like you | |
1377 | * saying you want anything less!!!!! | |
1378 | * They also expect page 00 | |
1379 | * back when you issue a mode select | |
1380 | */ | |
1381 | } scsi_sense_page_0; | |
1382 | struct st_data *st = st_data[unit]; | |
1383 | struct scsi_link *sc_link = st->sc_link; | |
15637ed4 | 1384 | |
519fb2b7 RG |
1385 | /* |
1386 | * Define what sort of structure we're working with | |
1387 | */ | |
1388 | if (st->quirks & ST_Q_NEEDS_PAGE_0) { | |
a0becc21 NW |
1389 | scsi_sense_len = sizeof(scsi_sense_page_0); |
1390 | scsi_sense_ptr = (char *) &scsi_sense_page_0; | |
519fb2b7 | 1391 | } else { |
a0becc21 NW |
1392 | scsi_sense_len = sizeof(scsi_sense); |
1393 | scsi_sense_ptr = (char *) &scsi_sense; | |
1394 | } | |
519fb2b7 RG |
1395 | /* |
1396 | * Set up a mode sense | |
1397 | */ | |
15637ed4 RG |
1398 | bzero(&scsi_cmd, sizeof(scsi_cmd)); |
1399 | scsi_cmd.op_code = MODE_SENSE; | |
a0becc21 NW |
1400 | scsi_cmd.length = scsi_sense_len; |
1401 | ||
519fb2b7 RG |
1402 | /* |
1403 | * do the command, but we don't need the results | |
1404 | * just print them for our interest's sake, if asked, | |
1405 | * or if we need it as a template for the mode select | |
1406 | * store it away. | |
1407 | */ | |
1408 | if (errno = scsi_scsi_cmd(sc_link, | |
1409 | (struct scsi_generic *) &scsi_cmd, | |
1410 | sizeof(scsi_cmd), | |
1411 | (u_char *) scsi_sense_ptr, | |
1412 | scsi_sense_len, | |
1413 | ST_RETRIES, | |
1414 | 5000, | |
1415 | NULL, | |
1416 | flags | SCSI_DATA_IN)) { | |
d4284689 | 1417 | return errno; |
519fb2b7 RG |
1418 | } |
1419 | st->numblks = _3btol(((struct scsi_sense *)scsi_sense_ptr)->blk_desc.nblocks); | |
1420 | st->media_blksiz = _3btol(((struct scsi_sense *)scsi_sense_ptr)->blk_desc.blklen); | |
1421 | st->media_density = ((struct scsi_sense *) scsi_sense_ptr)->blk_desc.density; | |
1422 | if (((struct scsi_sense *) scsi_sense_ptr)->header.dev_spec & | |
1423 | SMH_DSP_WRITE_PROT) { | |
d4284689 | 1424 | st->flags |= ST_READONLY; |
15637ed4 | 1425 | } |
519fb2b7 RG |
1426 | SC_DEBUG(sc_link, SDEV_DB3, |
1427 | ("density code 0x%x, %d-byte blocks, write-%s, ", | |
1428 | st->media_density, st->media_blksiz, | |
1429 | st->flags & ST_READONLY ? "protected" : "enabled")); | |
1430 | SC_DEBUG(sc_link, SDEV_DB3, | |
1431 | ("%sbuffered\n", | |
1432 | ((struct scsi_sense *) scsi_sense_ptr)->header.dev_spec | |
1433 | & SMH_DSP_BUFF_MODE ? "" : "un")); | |
1434 | if (st->quirks & ST_Q_NEEDS_PAGE_0) { | |
1435 | bcopy(((struct scsi_sense_page_0 *) scsi_sense_ptr)->sense_data, | |
1436 | st->sense_data, | |
1437 | sizeof(((struct scsi_sense_page_0 *) scsi_sense_ptr)->sense_data)); | |
a0becc21 | 1438 | } |
519fb2b7 | 1439 | sc_link->flags |= SDEV_MEDIA_LOADED; |
d4284689 | 1440 | return 0; |
15637ed4 RG |
1441 | } |
1442 | ||
519fb2b7 RG |
1443 | /* |
1444 | * Send a filled out parameter structure to the drive to | |
1445 | * set it into the desire modes etc. | |
1446 | */ | |
1447 | errval | |
d4284689 | 1448 | st_mode_select(unit, flags) |
519fb2b7 | 1449 | u_int32 unit, flags; |
15637ed4 | 1450 | { |
519fb2b7 RG |
1451 | u_int32 dat_len; |
1452 | char *dat_ptr; | |
15637ed4 | 1453 | struct scsi_mode_select scsi_cmd; |
519fb2b7 RG |
1454 | struct dat { |
1455 | struct scsi_mode_header header; | |
1456 | struct blk_desc blk_desc; | |
1457 | } dat; | |
1458 | struct dat_page_0 { | |
1459 | struct scsi_mode_header header; | |
1460 | struct blk_desc blk_desc; | |
1461 | unsigned char sense_data[PAGE_0_SENSE_DATA_SIZE]; | |
1462 | } dat_page_0; | |
1463 | struct st_data *st = st_data[unit]; | |
1464 | ||
1465 | /* | |
1466 | * Define what sort of structure we're working with | |
1467 | */ | |
1468 | if (st->quirks & ST_Q_NEEDS_PAGE_0) { | |
a0becc21 NW |
1469 | dat_len = sizeof(dat_page_0); |
1470 | dat_ptr = (char *) &dat_page_0; | |
519fb2b7 | 1471 | } else { |
a0becc21 NW |
1472 | dat_len = sizeof(dat); |
1473 | dat_ptr = (char *) &dat; | |
1474 | } | |
519fb2b7 RG |
1475 | /* |
1476 | * Set up for a mode select | |
1477 | */ | |
a0becc21 | 1478 | bzero(dat_ptr, dat_len); |
15637ed4 RG |
1479 | bzero(&scsi_cmd, sizeof(scsi_cmd)); |
1480 | scsi_cmd.op_code = MODE_SELECT; | |
a0becc21 | 1481 | scsi_cmd.length = dat_len; |
519fb2b7 RG |
1482 | ((struct dat *) dat_ptr)->header.blk_desc_len = sizeof(struct blk_desc); |
1483 | ((struct dat *) dat_ptr)->header.dev_spec |= SMH_DSP_BUFF_MODE_ON; | |
1484 | ((struct dat *) dat_ptr)->blk_desc.density = st->density; | |
1485 | if (st->flags & ST_FIXEDBLOCKS) { | |
1486 | lto3b(st->blksiz, ((struct dat *) dat_ptr)->blk_desc.blklen); | |
a0becc21 | 1487 | } |
519fb2b7 RG |
1488 | if (st->quirks & ST_Q_NEEDS_PAGE_0) { |
1489 | bcopy(st->sense_data, ((struct dat_page_0 *) dat_ptr)->sense_data, | |
1490 | sizeof(((struct dat_page_0 *) dat_ptr)->sense_data)); | |
1491 | /* the Tandberg tapes need the block size to */ | |
1492 | /* be set on each mode sense/select. */ | |
15637ed4 | 1493 | } |
519fb2b7 RG |
1494 | /* |
1495 | * do the command | |
1496 | */ | |
1497 | return (scsi_scsi_cmd(st->sc_link, | |
1498 | (struct scsi_generic *) &scsi_cmd, | |
1499 | sizeof(scsi_cmd), | |
1500 | (u_char *) dat_ptr, | |
1501 | dat_len, | |
1502 | ST_RETRIES, | |
1503 | 5000, | |
1504 | NULL, | |
1505 | flags | SCSI_DATA_OUT)); | |
15637ed4 RG |
1506 | } |
1507 | ||
519fb2b7 RG |
1508 | /* |
1509 | * skip N blocks/filemarks/seq filemarks/eom | |
1510 | */ | |
1511 | errval | |
1512 | st_space(unit, number, what, flags) | |
1513 | u_int32 unit, what, flags; | |
1514 | int32 number; | |
15637ed4 | 1515 | { |
519fb2b7 | 1516 | errval error; |
15637ed4 | 1517 | struct scsi_space scsi_cmd; |
519fb2b7 | 1518 | struct st_data *st = st_data[unit]; |
15637ed4 | 1519 | |
fde1aeb2 | 1520 | switch ((int)what) { |
519fb2b7 RG |
1521 | case SP_BLKS: |
1522 | if (st->flags & ST_PER_ACTION) { | |
1523 | if (number > 0) { | |
fca1f689 | 1524 | st->flags &= ~ST_PER_ACTION; |
519fb2b7 RG |
1525 | return (EIO); |
1526 | } else if (number < 0) { | |
1527 | if (st->flags & ST_AT_FILEMARK) { | |
1528 | /* | |
1529 | * Handling of ST_AT_FILEMARK | |
1530 | * in st_space will fill in the | |
1531 | * right file mark count. | |
1532 | */ | |
fca1f689 RG |
1533 | error = st_space(unit, 0, SP_FILEMARKS, |
1534 | flags); | |
519fb2b7 RG |
1535 | if (error) |
1536 | return (error); | |
fca1f689 | 1537 | } |
519fb2b7 | 1538 | if (st->flags & ST_BLANK_READ) { |
fca1f689 | 1539 | st->flags &= ~ST_BLANK_READ; |
519fb2b7 | 1540 | return (EIO); |
fca1f689 RG |
1541 | } |
1542 | st->flags &= ~ST_EIO_PENDING; | |
1543 | } | |
1544 | } | |
1545 | break; | |
519fb2b7 RG |
1546 | case SP_FILEMARKS: |
1547 | if (st->flags & ST_EIO_PENDING) { | |
1548 | if (number > 0) { /* pretend we just discover the error */ | |
fca1f689 | 1549 | st->flags &= ~ST_EIO_PENDING; |
519fb2b7 RG |
1550 | return (EIO); |
1551 | } else if (number < 0) { /* back away from the error */ | |
fca1f689 | 1552 | st->flags &= ~ST_EIO_PENDING; |
519fb2b7 | 1553 | } |
fca1f689 | 1554 | } |
519fb2b7 | 1555 | if (st->flags & ST_AT_FILEMARK) { |
fca1f689 RG |
1556 | st->flags &= ~ST_AT_FILEMARK; |
1557 | number--; | |
1558 | } | |
519fb2b7 | 1559 | if ((st->flags & ST_BLANK_READ) && (number < 0)) { /* back away from unwritten tape */ |
fca1f689 | 1560 | st->flags &= ~ST_BLANK_READ; |
519fb2b7 | 1561 | number++; /* dubious */ |
fca1f689 RG |
1562 | } |
1563 | } | |
519fb2b7 RG |
1564 | if (number == 0) { |
1565 | return (ESUCCESS); | |
1566 | } | |
15637ed4 RG |
1567 | bzero(&scsi_cmd, sizeof(scsi_cmd)); |
1568 | scsi_cmd.op_code = SPACE; | |
869c4419 | 1569 | scsi_cmd.byte2 = what & SS_CODE; |
519fb2b7 RG |
1570 | lto3b(number, scsi_cmd.number); |
1571 | return (scsi_scsi_cmd(st->sc_link, | |
1572 | (struct scsi_generic *) &scsi_cmd, | |
1573 | sizeof(scsi_cmd), | |
1574 | 0, | |
1575 | 0, | |
1576 | 0, /* no retries please , just fail */ | |
1577 | 600000, /* 10 mins enough? */ | |
1578 | NULL, | |
1579 | flags)); | |
15637ed4 | 1580 | } |
519fb2b7 RG |
1581 | |
1582 | /* | |
1583 | * write N filemarks | |
1584 | */ | |
1585 | errval | |
1586 | st_write_filemarks(unit, number, flags) | |
1587 | u_int32 unit, flags; | |
1588 | int32 number; | |
15637ed4 RG |
1589 | { |
1590 | struct scsi_write_filemarks scsi_cmd; | |
519fb2b7 | 1591 | struct st_data *st = st_data[unit]; |
15637ed4 | 1592 | |
519fb2b7 RG |
1593 | /* |
1594 | * It's hard to write a negative number of file marks. | |
1595 | * Don't try. | |
1596 | */ | |
1597 | if (number < 0) { | |
1598 | return EINVAL; | |
1599 | } | |
fde1aeb2 | 1600 | switch ((int)number) { |
519fb2b7 | 1601 | case 0: /* really a command to sync the drive's buffers */ |
fca1f689 | 1602 | break; |
519fb2b7 RG |
1603 | case 1: |
1604 | if (st->flags & ST_FM_WRITTEN) { /* already have one down */ | |
fca1f689 | 1605 | st->flags &= ~ST_WRITTEN; |
519fb2b7 | 1606 | } else { |
fca1f689 | 1607 | st->flags |= ST_FM_WRITTEN; |
519fb2b7 | 1608 | } |
fca1f689 RG |
1609 | st->flags &= ~ST_PER_ACTION; |
1610 | break; | |
1611 | default: | |
1612 | st->flags &= ~(ST_PER_ACTION | ST_WRITTEN); | |
1613 | } | |
15637ed4 RG |
1614 | bzero(&scsi_cmd, sizeof(scsi_cmd)); |
1615 | scsi_cmd.op_code = WRITE_FILEMARKS; | |
519fb2b7 RG |
1616 | lto3b(number, scsi_cmd.number); |
1617 | return scsi_scsi_cmd(st->sc_link, | |
1618 | (struct scsi_generic *) &scsi_cmd, | |
1619 | sizeof(scsi_cmd), | |
1620 | 0, | |
1621 | 0, | |
1622 | 0, /* no retries, just fail */ | |
1623 | 100000, /* 10 secs.. (may need to repos head ) */ | |
1624 | NULL, | |
1625 | flags); | |
15637ed4 | 1626 | } |
fca1f689 | 1627 | |
519fb2b7 RG |
1628 | /* |
1629 | * Make sure the right number of file marks is on tape if the | |
1630 | * tape has been written. If the position argument is true, | |
1631 | * leave the tape positioned where it was originally. | |
1632 | * | |
1633 | * nmarks returns the number of marks to skip (or, if position | |
1634 | * true, which were skipped) to get back original position. | |
1635 | */ | |
1636 | int32 | |
fca1f689 | 1637 | st_chkeod(unit, position, nmarks, flags) |
519fb2b7 RG |
1638 | u_int32 unit; |
1639 | boolean position; | |
1640 | int32 *nmarks; | |
1641 | u_int32 flags; | |
fca1f689 | 1642 | { |
519fb2b7 RG |
1643 | errval error; |
1644 | struct st_data *st = st_data[unit]; | |
fca1f689 | 1645 | |
fde1aeb2 | 1646 | switch ((int)(st->flags & (ST_WRITTEN | ST_FM_WRITTEN | ST_2FM_AT_EOD))) { |
fca1f689 RG |
1647 | default: |
1648 | *nmarks = 0; | |
519fb2b7 RG |
1649 | return (ESUCCESS); |
1650 | case ST_WRITTEN: | |
1651 | case ST_WRITTEN | ST_FM_WRITTEN | ST_2FM_AT_EOD: | |
fca1f689 RG |
1652 | *nmarks = 1; |
1653 | break; | |
519fb2b7 | 1654 | case ST_WRITTEN | ST_2FM_AT_EOD: |
fca1f689 RG |
1655 | *nmarks = 2; |
1656 | } | |
1657 | error = st_write_filemarks(unit, *nmarks, flags); | |
519fb2b7 | 1658 | if (position && (error == ESUCCESS)) |
fca1f689 RG |
1659 | error = st_space(unit, -*nmarks, SP_FILEMARKS, flags); |
1660 | return (error); | |
1661 | } | |
1662 | ||
519fb2b7 RG |
1663 | /* |
1664 | * load/unload (with retension if true) | |
1665 | */ | |
1666 | errval | |
1667 | st_load(unit, type, flags) | |
1668 | u_int32 unit, type, flags; | |
15637ed4 | 1669 | { |
519fb2b7 RG |
1670 | struct scsi_load scsi_cmd; |
1671 | struct st_data *st = st_data[unit]; | |
1672 | struct scsi_link *sc_link = st->sc_link; | |
15637ed4 | 1673 | |
15637ed4 | 1674 | bzero(&scsi_cmd, sizeof(scsi_cmd)); |
519fb2b7 RG |
1675 | if (type != LD_LOAD) { |
1676 | errval error; | |
1677 | int32 nmarks; | |
fca1f689 RG |
1678 | |
1679 | error = st_chkeod(unit, FALSE, &nmarks, flags); | |
519fb2b7 RG |
1680 | if (error != ESUCCESS) |
1681 | return (error); | |
1682 | sc_link->flags &= ~SDEV_MEDIA_LOADED; | |
fca1f689 | 1683 | } |
519fb2b7 RG |
1684 | if (st->quirks & ST_Q_IGNORE_LOADS) |
1685 | return (0); | |
fca1f689 RG |
1686 | scsi_cmd.op_code = LOAD_UNLOAD; |
1687 | scsi_cmd.how |= type; | |
519fb2b7 RG |
1688 | return (scsi_scsi_cmd(st->sc_link, |
1689 | (struct scsi_generic *) &scsi_cmd, | |
1690 | sizeof(scsi_cmd), | |
1691 | 0, | |
1692 | 0, | |
1693 | ST_RETRIES, | |
1694 | 300000, /* 5 min */ | |
1695 | NULL, | |
1696 | flags)); | |
15637ed4 | 1697 | } |
fca1f689 | 1698 | |
519fb2b7 RG |
1699 | /* |
1700 | * Rewind the device | |
1701 | */ | |
1702 | errval | |
1703 | st_rewind(unit, immed, flags) | |
1704 | u_int32 unit, flags; | |
1705 | boolean immed; | |
15637ed4 | 1706 | { |
519fb2b7 RG |
1707 | struct scsi_rewind scsi_cmd; |
1708 | struct st_data *st = st_data[unit]; | |
1709 | errval error; | |
1710 | int32 nmarks; | |
15637ed4 | 1711 | |
fca1f689 | 1712 | error = st_chkeod(unit, FALSE, &nmarks, flags); |
519fb2b7 RG |
1713 | if (error != ESUCCESS) |
1714 | return (error); | |
d4284689 | 1715 | st->flags &= ~ST_PER_ACTION; |
15637ed4 RG |
1716 | bzero(&scsi_cmd, sizeof(scsi_cmd)); |
1717 | scsi_cmd.op_code = REWIND; | |
d4284689 | 1718 | scsi_cmd.byte2 = immed ? SR_IMMED : 0; |
519fb2b7 RG |
1719 | return (scsi_scsi_cmd(st->sc_link, |
1720 | (struct scsi_generic *) &scsi_cmd, | |
1721 | sizeof(scsi_cmd), | |
1722 | 0, | |
1723 | 0, | |
1724 | ST_RETRIES, | |
1725 | immed ? 5000 : 300000, /* 5 sec or 5 min */ | |
1726 | NULL, | |
1727 | flags)); | |
d4284689 RG |
1728 | } |
1729 | ||
519fb2b7 RG |
1730 | #ifdef NETBSD |
1731 | #define SIGNAL_SHORT_READ | |
d4284689 | 1732 | #else |
519fb2b7 RG |
1733 | #define SIGNAL_SHORT_READ bp->b_flags |= B_ERROR; |
1734 | #endif | |
d4284689 | 1735 | |
519fb2b7 RG |
1736 | /* |
1737 | * Look at the returned sense and act on the error and detirmine | |
1738 | * The unix error number to pass back... (0 = report no error) | |
1739 | * (-1 = continue processing) | |
1740 | */ | |
1741 | errval | |
1742 | st_interpret_sense(xs) | |
1743 | struct scsi_xfer *xs; | |
d4284689 | 1744 | { |
519fb2b7 RG |
1745 | struct scsi_link *sc_link = xs->sc_link; |
1746 | struct scsi_sense_data *sense = &(xs->sense); | |
1747 | boolean silent = xs->flags & SCSI_SILENT; | |
1748 | struct buf *bp = xs->bp; | |
1749 | u_int32 unit = sc_link->dev_unit; | |
1750 | struct st_data *st = st_data[unit]; | |
1751 | u_int32 key; | |
1752 | int32 info; | |
1753 | ||
1754 | /* | |
1755 | * Get the sense fields and work out what code | |
1756 | */ | |
1757 | if (sense->error_code & SSD_ERRCODE_VALID) { | |
1758 | info = ntohl(*((int32 *) sense->ext.extended.info)); | |
1759 | } else { | |
1760 | info = xs->datalen; /* bad choice if fixed blocks */ | |
d4284689 | 1761 | } |
519fb2b7 RG |
1762 | if ((sense->error_code & SSD_ERRCODE) != 0x70) { |
1763 | return (-1); /* let the generic code handle it */ | |
d4284689 | 1764 | } |
519fb2b7 RG |
1765 | if (st->flags & ST_FIXEDBLOCKS) { |
1766 | xs->resid = info * st->blksiz; | |
1767 | if (sense->ext.extended.flags & SSD_EOM) { | |
1768 | st->flags |= ST_EIO_PENDING; | |
1769 | if (bp) { | |
1770 | bp->b_resid = xs->resid; | |
1771 | SIGNAL_SHORT_READ | |
d4284689 | 1772 | } |
15637ed4 | 1773 | } |
519fb2b7 RG |
1774 | if (sense->ext.extended.flags & SSD_FILEMARK) { |
1775 | st->flags |= ST_AT_FILEMARK; | |
1776 | if (bp) { | |
1777 | bp->b_resid = xs->resid; | |
1778 | SIGNAL_SHORT_READ | |
1779 | } | |
15637ed4 | 1780 | } |
519fb2b7 RG |
1781 | if (sense->ext.extended.flags & SSD_ILI) { |
1782 | st->flags |= ST_EIO_PENDING; | |
1783 | if (bp) { | |
1784 | bp->b_resid = xs->resid; | |
1785 | SIGNAL_SHORT_READ | |
d4284689 | 1786 | } |
519fb2b7 RG |
1787 | if (sense->error_code & SSD_ERRCODE_VALID && |
1788 | !silent) | |
1789 | printf("st%d: block wrong size" | |
1790 | ", %d blocks residual\n", unit | |
1791 | ,info); | |
1792 | ||
1793 | /* | |
1794 | * This quirk code helps the drive read | |
1795 | * the first tape block, regardless of | |
1796 | * format. That is required for these | |
1797 | * drives to return proper MODE SENSE | |
1798 | * information. | |
1799 | */ | |
1800 | if ((st->quirks & ST_Q_SNS_HLP) && | |
1801 | !(sc_link->flags & SDEV_MEDIA_LOADED)) { | |
1802 | st->blksiz -= 512; | |
d4284689 | 1803 | } |
519fb2b7 RG |
1804 | } |
1805 | /* | |
1806 | * If no data was tranfered, do it immediatly | |
1807 | */ | |
1808 | if (xs->resid >= xs->datalen) { | |
1809 | if (st->flags & ST_EIO_PENDING) { | |
1810 | return EIO; | |
d4284689 | 1811 | } |
519fb2b7 RG |
1812 | if (st->flags & ST_AT_FILEMARK) { |
1813 | if (bp) { | |
1814 | bp->b_resid = xs->resid; | |
1815 | SIGNAL_SHORT_READ | |
d4284689 | 1816 | } |
519fb2b7 | 1817 | return 0; |
d4284689 | 1818 | } |
15637ed4 | 1819 | } |
519fb2b7 RG |
1820 | } else { /* must be variable mode */ |
1821 | xs->resid = xs->datalen; /* to be sure */ | |
1822 | if (sense->ext.extended.flags & SSD_EOM) { | |
1823 | return (EIO); | |
1824 | } | |
1825 | if (sense->ext.extended.flags & SSD_FILEMARK) { | |
1826 | if (bp) | |
1827 | bp->b_resid = bp->b_bcount; | |
1828 | return 0; | |
1829 | } | |
1830 | if (sense->ext.extended.flags & SSD_ILI) { | |
1831 | if (info < 0) { | |
1832 | /* | |
1833 | * the record was bigger than the read | |
1834 | */ | |
1835 | if (!silent) | |
1836 | printf("st%d: %d-byte record " | |
1837 | "too big\n", unit, | |
1838 | xs->datalen - info); | |
1839 | return (EIO); | |
15637ed4 | 1840 | } |
519fb2b7 RG |
1841 | xs->resid = info; |
1842 | if (bp) { | |
1843 | bp->b_resid = info; | |
1844 | SIGNAL_SHORT_READ | |
d4284689 | 1845 | } |
519fb2b7 RG |
1846 | } |
1847 | } | |
1848 | key = sense->ext.extended.flags & SSD_KEY; | |
1849 | ||
1850 | if (key == 0x8) { | |
1851 | /* | |
1852 | * This quirk code helps the drive read the | |
1853 | * first tape block, regardless of format. That | |
1854 | * is required for these drives to return proper | |
1855 | * MODE SENSE information. | |
1856 | */ | |
1857 | if ((st->quirks & ST_Q_SNS_HLP) && | |
1858 | !(sc_link->flags & SDEV_MEDIA_LOADED)) { /* still starting */ | |
1859 | st->blksiz -= 512; | |
1860 | } else if (!(st->flags & (ST_2FM_AT_EOD | ST_BLANK_READ))) { | |
1861 | st->flags |= ST_BLANK_READ; | |
1862 | xs->resid = xs->datalen; | |
1863 | if (bp) { | |
1864 | bp->b_resid = xs->resid; | |
1865 | /*return an EOF */ | |
15637ed4 | 1866 | } |
519fb2b7 RG |
1867 | return (ESUCCESS); |
1868 | } | |
1869 | } | |
1870 | return (-1); /* let the default/generic handler handle it */ | |
1871 | } | |
15637ed4 | 1872 | |
519fb2b7 RG |
1873 | /* |
1874 | * The quirk here is that the drive returns some value to st_mode_sense | |
1875 | * incorrectly until the tape has actually passed by the head. | |
1876 | * | |
1877 | * The method is to set the drive to large fixed-block state (user-specified | |
1878 | * density and 1024-byte blocks), then read and rewind to get it to sense the | |
1879 | * tape. If that doesn't work, try 512-byte fixed blocks. If that doesn't | |
1880 | * work, as a last resort, try variable- length blocks. The result will be | |
1881 | * the ability to do an accurate st_mode_sense. | |
1882 | * | |
1883 | * We know we can do a rewind because we just did a load, which implies rewind. | |
1884 | * Rewind seems preferable to space backward if we have a virgin tape. | |
1885 | * | |
1886 | * The rest of the code for this quirk is in ILI processing and BLANK CHECK | |
1887 | * error processing, both part of st_interpret_sense. | |
1888 | */ | |
1889 | errval | |
1890 | st_touch_tape(unit) | |
1891 | u_int32 unit; | |
1892 | { | |
1893 | struct st_data *st = st_data[unit]; | |
1894 | char *buf; | |
1895 | u_int32 readsiz; | |
1896 | errval errno; | |
0269d546 | 1897 | |
519fb2b7 RG |
1898 | buf = malloc(1024, M_TEMP, M_NOWAIT); |
1899 | if (!buf) | |
1900 | return (ENOMEM); | |
0269d546 | 1901 | |
519fb2b7 RG |
1902 | if (errno = st_mode_sense(unit, 0)) { |
1903 | goto bad; | |
1904 | } | |
1905 | st->blksiz = 1024; | |
1906 | do { | |
fde1aeb2 | 1907 | switch ((int)st->blksiz) { |
519fb2b7 RG |
1908 | case 512: |
1909 | case 1024: | |
1910 | readsiz = st->blksiz; | |
1911 | st->flags |= ST_FIXEDBLOCKS; | |
1912 | break; | |
0269d546 | 1913 | default: |
519fb2b7 RG |
1914 | readsiz = 1; |
1915 | st->flags &= ~ST_FIXEDBLOCKS; | |
1916 | } if (errno = st_mode_select(unit, 0)) { | |
1917 | goto bad; | |
15637ed4 | 1918 | } |
519fb2b7 RG |
1919 | st_read(unit, buf, readsiz, SCSI_SILENT); |
1920 | if (errno = st_rewind(unit, FALSE, 0)) { | |
1921 | bad: free(buf, M_TEMP); | |
1922 | return (errno); | |
15637ed4 | 1923 | } |
519fb2b7 RG |
1924 | } while (readsiz != 1 && readsiz > st->blksiz); |
1925 | free(buf, M_TEMP); | |
1926 | return 0; | |
15637ed4 | 1927 | } |