1 | /* $NetBSD: sd.c,v 1.319 2016/11/20 15:37:19 mlelstv Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 1998, 2003, 2004 The NetBSD Foundation, Inc. |
5 | * All rights reserved. |
6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Charles M. Hannum. |
9 | * |
10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions |
12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. |
18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ |
31 | |
32 | /* |
33 | * Originally written by Julian Elischer (julian@dialix.oz.au) |
34 | * for TRW Financial Systems for use under the MACH(2.5) operating system. |
35 | * |
36 | * TRW Financial Systems, in accordance with their agreement with Carnegie |
37 | * Mellon University, makes this software available to CMU to distribute |
38 | * or use in any manner that they see fit as long as this message is kept with |
39 | * the software. For this reason TFS also grants any other persons or |
40 | * organisations permission to use or modify this software. |
41 | * |
42 | * TFS supplies this software to be publicly redistributed |
43 | * on the understanding that TFS is not responsible for the correct |
44 | * functioning of this software in any circumstances. |
45 | * |
46 | * Ported to run under 386BSD by Julian Elischer (julian@dialix.oz.au) Sept 1992 |
47 | */ |
48 | |
49 | #include <sys/cdefs.h> |
50 | __KERNEL_RCSID(0, "$NetBSD: sd.c,v 1.319 2016/11/20 15:37:19 mlelstv Exp $" ); |
51 | |
52 | #ifdef _KERNEL_OPT |
53 | #include "opt_scsi.h" |
54 | #endif |
55 | |
56 | #define SD_MPSAFE D_MPSAFE |
57 | |
58 | #include <sys/param.h> |
59 | #include <sys/systm.h> |
60 | #include <sys/kernel.h> |
61 | #include <sys/file.h> |
62 | #include <sys/stat.h> |
63 | #include <sys/ioctl.h> |
64 | #include <sys/scsiio.h> |
65 | #include <sys/buf.h> |
66 | #include <sys/bufq.h> |
67 | #include <sys/uio.h> |
68 | #include <sys/malloc.h> |
69 | #include <sys/errno.h> |
70 | #include <sys/device.h> |
71 | #include <sys/disklabel.h> |
72 | #include <sys/disk.h> |
73 | #include <sys/proc.h> |
74 | #include <sys/conf.h> |
75 | #include <sys/vnode.h> |
76 | #include <sys/rndsource.h> |
77 | |
78 | #include <dev/scsipi/scsi_spc.h> |
79 | #include <dev/scsipi/scsipi_all.h> |
80 | #include <dev/scsipi/scsi_all.h> |
81 | #include <dev/scsipi/scsipi_disk.h> |
82 | #include <dev/scsipi/scsi_disk.h> |
83 | #include <dev/scsipi/scsiconf.h> |
84 | #include <dev/scsipi/scsipi_base.h> |
85 | #include <dev/scsipi/sdvar.h> |
86 | |
87 | #include <prop/proplib.h> |
88 | |
89 | #define SDUNIT(dev) DISKUNIT(dev) |
90 | #define SDPART(dev) DISKPART(dev) |
91 | #define SDMINOR(unit, part) DISKMINOR(unit, part) |
92 | #define MAKESDDEV(maj, unit, part) MAKEDISKDEV(maj, unit, part) |
93 | |
94 | #define SDLABELDEV(dev) (MAKESDDEV(major(dev), SDUNIT(dev), RAW_PART)) |
95 | |
96 | #define SD_DEFAULT_BLKSIZE 512 |
97 | |
98 | static void sdminphys(struct buf *); |
99 | static void sdgetdefaultlabel(struct sd_softc *, struct disklabel *); |
100 | static int sdgetdisklabel(struct sd_softc *); |
101 | static void sdstart(struct scsipi_periph *); |
102 | static void sdrestart(void *); |
103 | static void sddone(struct scsipi_xfer *, int); |
104 | static bool sd_suspend(device_t, const pmf_qual_t *); |
105 | static bool sd_shutdown(device_t, int); |
106 | static int sd_interpret_sense(struct scsipi_xfer *); |
107 | static int sdlastclose(device_t); |
108 | |
109 | static int sd_mode_sense(struct sd_softc *, u_int8_t, void *, size_t, int, |
110 | int, int *); |
111 | static int sd_mode_select(struct sd_softc *, u_int8_t, void *, size_t, int, |
112 | int); |
113 | static int sd_validate_blksize(struct scsipi_periph *, int); |
114 | static u_int64_t sd_read_capacity(struct scsipi_periph *, int *, int flags); |
115 | static int sd_get_simplifiedparms(struct sd_softc *, struct disk_parms *, |
116 | int); |
117 | static int sd_get_capacity(struct sd_softc *, struct disk_parms *, int); |
118 | static int sd_get_parms(struct sd_softc *, struct disk_parms *, int); |
119 | static int sd_get_parms_page4(struct sd_softc *, struct disk_parms *, |
120 | int); |
121 | static int sd_get_parms_page5(struct sd_softc *, struct disk_parms *, |
122 | int); |
123 | |
124 | static int sd_flush(struct sd_softc *, int); |
125 | static int sd_getcache(struct sd_softc *, int *); |
126 | static int sd_setcache(struct sd_softc *, int); |
127 | |
128 | static int sdmatch(device_t, cfdata_t, void *); |
129 | static void sdattach(device_t, device_t, void *); |
130 | static int sddetach(device_t, int); |
131 | static void sd_set_geometry(struct sd_softc *); |
132 | |
133 | CFATTACH_DECL3_NEW(sd, sizeof(struct sd_softc), sdmatch, sdattach, sddetach, |
134 | NULL, NULL, NULL, DVF_DETACH_SHUTDOWN); |
135 | |
136 | extern struct cfdriver sd_cd; |
137 | |
138 | static const struct scsipi_inquiry_pattern sd_patterns[] = { |
139 | {T_DIRECT, T_FIXED, |
140 | "" , "" , "" }, |
141 | {T_DIRECT, T_REMOV, |
142 | "" , "" , "" }, |
143 | {T_OPTICAL, T_FIXED, |
144 | "" , "" , "" }, |
145 | {T_OPTICAL, T_REMOV, |
146 | "" , "" , "" }, |
147 | {T_SIMPLE_DIRECT, T_FIXED, |
148 | "" , "" , "" }, |
149 | {T_SIMPLE_DIRECT, T_REMOV, |
150 | "" , "" , "" }, |
151 | }; |
152 | |
153 | static dev_type_open(sdopen); |
154 | static dev_type_close(sdclose); |
155 | static dev_type_read(sdread); |
156 | static dev_type_write(sdwrite); |
157 | static dev_type_ioctl(sdioctl); |
158 | static dev_type_strategy(sdstrategy); |
159 | static dev_type_dump(sddump); |
160 | static dev_type_size(sdsize); |
161 | |
162 | const struct bdevsw sd_bdevsw = { |
163 | .d_open = sdopen, |
164 | .d_close = sdclose, |
165 | .d_strategy = sdstrategy, |
166 | .d_ioctl = sdioctl, |
167 | .d_dump = sddump, |
168 | .d_psize = sdsize, |
169 | .d_discard = nodiscard, |
170 | .d_flag = D_DISK | SD_MPSAFE |
171 | }; |
172 | |
173 | const struct cdevsw sd_cdevsw = { |
174 | .d_open = sdopen, |
175 | .d_close = sdclose, |
176 | .d_read = sdread, |
177 | .d_write = sdwrite, |
178 | .d_ioctl = sdioctl, |
179 | .d_stop = nostop, |
180 | .d_tty = notty, |
181 | .d_poll = nopoll, |
182 | .d_mmap = nommap, |
183 | .d_kqfilter = nokqfilter, |
184 | .d_discard = nodiscard, |
185 | .d_flag = D_DISK | SD_MPSAFE |
186 | }; |
187 | |
188 | static struct dkdriver sddkdriver = { |
189 | .d_strategy = sdstrategy, |
190 | .d_minphys = sdminphys |
191 | }; |
192 | |
193 | static const struct scsipi_periphsw sd_switch = { |
194 | sd_interpret_sense, /* check our error handler first */ |
195 | sdstart, /* have a queue, served by this */ |
196 | NULL, /* have no async handler */ |
197 | sddone, /* deal with stats at interrupt time */ |
198 | }; |
199 | |
200 | struct sd_mode_sense_data { |
201 | /* |
202 | * XXX |
203 | * We are not going to parse this as-is -- it just has to be large |
204 | * enough. |
205 | */ |
206 | union { |
207 | struct scsi_mode_parameter_header_6 small; |
208 | struct scsi_mode_parameter_header_10 big; |
209 | } ; |
210 | struct scsi_general_block_descriptor blk_desc; |
211 | union scsi_disk_pages pages; |
212 | }; |
213 | |
214 | /* |
215 | * The routine called by the low level scsi routine when it discovers |
216 | * A device suitable for this driver |
217 | */ |
218 | static int |
219 | sdmatch(device_t parent, cfdata_t match, |
220 | void *aux) |
221 | { |
222 | struct scsipibus_attach_args *sa = aux; |
223 | int priority; |
224 | |
225 | (void)scsipi_inqmatch(&sa->sa_inqbuf, |
226 | sd_patterns, sizeof(sd_patterns) / sizeof(sd_patterns[0]), |
227 | sizeof(sd_patterns[0]), &priority); |
228 | |
229 | return (priority); |
230 | } |
231 | |
232 | /* |
233 | * Attach routine common to atapi & scsi. |
234 | */ |
235 | static void |
236 | sdattach(device_t parent, device_t self, void *aux) |
237 | { |
238 | struct sd_softc *sd = device_private(self); |
239 | struct scsipibus_attach_args *sa = aux; |
240 | struct scsipi_periph *periph = sa->sa_periph; |
241 | int error, result; |
242 | struct disk_parms *dp = &sd->params; |
243 | char pbuf[9]; |
244 | |
245 | SC_DEBUG(periph, SCSIPI_DB2, ("sdattach: " )); |
246 | |
247 | sd->sc_dev = self; |
248 | sd->type = (sa->sa_inqbuf.type & SID_TYPE); |
249 | strncpy(sd->name, sa->sa_inqbuf.product, sizeof(sd->name)); |
250 | if (sd->type == T_SIMPLE_DIRECT) |
251 | periph->periph_quirks |= PQUIRK_ONLYBIG | PQUIRK_NOBIGMODESENSE; |
252 | |
253 | if (SCSIPI_BUSTYPE_TYPE(scsipi_periph_bustype(sa->sa_periph)) == |
254 | SCSIPI_BUSTYPE_SCSI && periph->periph_version == 0) |
255 | sd->flags |= SDF_ANCIENT; |
256 | |
257 | bufq_alloc(&sd->buf_queue, BUFQ_DISK_DEFAULT_STRAT, BUFQ_SORT_RAWBLOCK); |
258 | |
259 | callout_init(&sd->sc_callout, 0); |
260 | |
261 | /* |
262 | * Store information needed to contact our base driver |
263 | */ |
264 | sd->sc_periph = periph; |
265 | |
266 | periph->periph_dev = sd->sc_dev; |
267 | periph->periph_switch = &sd_switch; |
268 | |
269 | /* |
270 | * Increase our openings to the maximum-per-periph |
271 | * supported by the adapter. This will either be |
272 | * clamped down or grown by the adapter if necessary. |
273 | */ |
274 | periph->periph_openings = |
275 | SCSIPI_CHAN_MAX_PERIPH(periph->periph_channel); |
276 | periph->periph_flags |= PERIPH_GROW_OPENINGS; |
277 | |
278 | /* |
279 | * Initialize and attach the disk structure. |
280 | */ |
281 | disk_init(&sd->sc_dk, device_xname(sd->sc_dev), &sddkdriver); |
282 | disk_attach(&sd->sc_dk); |
283 | |
284 | /* |
285 | * Use the subdriver to request information regarding the drive. |
286 | */ |
287 | aprint_naive("\n" ); |
288 | aprint_normal("\n" ); |
289 | |
290 | if (periph->periph_quirks & PQUIRK_START) |
291 | (void)scsipi_start(periph, SSS_START, XS_CTL_SILENT); |
292 | |
293 | error = scsipi_test_unit_ready(periph, |
294 | XS_CTL_DISCOVERY | XS_CTL_IGNORE_ILLEGAL_REQUEST | |
295 | XS_CTL_IGNORE_MEDIA_CHANGE | XS_CTL_SILENT_NODEV); |
296 | |
297 | if (error) |
298 | result = SDGP_RESULT_OFFLINE; |
299 | else |
300 | result = sd_get_parms(sd, &sd->params, XS_CTL_DISCOVERY); |
301 | aprint_normal_dev(sd->sc_dev, "" ); |
302 | switch (result) { |
303 | case SDGP_RESULT_OK: |
304 | format_bytes(pbuf, sizeof(pbuf), |
305 | (u_int64_t)dp->disksize * dp->blksize); |
306 | aprint_normal( |
307 | "%s, %ld cyl, %ld head, %ld sec, %ld bytes/sect x %llu sectors" , |
308 | pbuf, dp->cyls, dp->heads, dp->sectors, dp->blksize, |
309 | (unsigned long long)dp->disksize); |
310 | break; |
311 | |
312 | case SDGP_RESULT_OFFLINE: |
313 | aprint_normal("drive offline" ); |
314 | break; |
315 | |
316 | case SDGP_RESULT_UNFORMATTED: |
317 | aprint_normal("unformatted media" ); |
318 | break; |
319 | |
320 | #ifdef DIAGNOSTIC |
321 | default: |
322 | panic("sdattach: unknown result from get_parms" ); |
323 | break; |
324 | #endif |
325 | } |
326 | aprint_normal("\n" ); |
327 | |
328 | /* |
329 | * Establish a shutdown hook so that we can ensure that |
330 | * our data has actually made it onto the platter at |
331 | * shutdown time. Note that this relies on the fact |
332 | * that the shutdown hooks at the "leaves" of the device tree |
333 | * are run, first (thus guaranteeing that our hook runs before |
334 | * our ancestors'). |
335 | */ |
336 | if (!pmf_device_register1(self, sd_suspend, NULL, sd_shutdown)) |
337 | aprint_error_dev(self, "couldn't establish power handler\n" ); |
338 | |
339 | /* |
340 | * attach the device into the random source list |
341 | */ |
342 | rnd_attach_source(&sd->rnd_source, device_xname(sd->sc_dev), |
343 | RND_TYPE_DISK, RND_FLAG_DEFAULT); |
344 | |
345 | /* Discover wedges on this disk. */ |
346 | dkwedge_discover(&sd->sc_dk); |
347 | |
348 | /* |
349 | * Disk insertion and removal times can be a useful source |
350 | * of entropy, though the estimator should never _count_ |
351 | * these bits, on insertion, because the deltas to the |
352 | * nonexistent) previous event should never allow it. |
353 | */ |
354 | rnd_add_uint32(&sd->rnd_source, 0); |
355 | } |
356 | |
357 | static int |
358 | sddetach(device_t self, int flags) |
359 | { |
360 | struct sd_softc *sd = device_private(self); |
361 | struct scsipi_periph *periph = sd->sc_periph; |
362 | struct scsipi_channel *chan = periph->periph_channel; |
363 | int bmaj, cmaj, i, mn, rc; |
364 | |
365 | rnd_add_uint32(&sd->rnd_source, 0); |
366 | |
367 | if ((rc = disk_begindetach(&sd->sc_dk, sdlastclose, self, flags)) != 0) |
368 | return rc; |
369 | |
370 | /* locate the major number */ |
371 | bmaj = bdevsw_lookup_major(&sd_bdevsw); |
372 | cmaj = cdevsw_lookup_major(&sd_cdevsw); |
373 | |
374 | /* Nuke the vnodes for any open instances */ |
375 | for (i = 0; i < MAXPARTITIONS; i++) { |
376 | mn = SDMINOR(device_unit(self), i); |
377 | vdevgone(bmaj, mn, mn, VBLK); |
378 | vdevgone(cmaj, mn, mn, VCHR); |
379 | } |
380 | |
381 | /* kill any pending restart */ |
382 | callout_stop(&sd->sc_callout); |
383 | |
384 | /* Delete all of our wedges. */ |
385 | dkwedge_delall(&sd->sc_dk); |
386 | |
387 | mutex_enter(chan_mtx(chan)); |
388 | |
389 | /* Kill off any queued buffers. */ |
390 | bufq_drain(sd->buf_queue); |
391 | |
392 | /* Kill off any pending commands. */ |
393 | scsipi_kill_pending(sd->sc_periph); |
394 | |
395 | mutex_exit(chan_mtx(chan)); |
396 | |
397 | bufq_free(sd->buf_queue); |
398 | |
399 | /* Detach from the disk list. */ |
400 | disk_detach(&sd->sc_dk); |
401 | disk_destroy(&sd->sc_dk); |
402 | |
403 | callout_destroy(&sd->sc_callout); |
404 | |
405 | pmf_device_deregister(self); |
406 | |
407 | /* Unhook the entropy source. */ |
408 | rnd_detach_source(&sd->rnd_source); |
409 | |
410 | return (0); |
411 | } |
412 | |
413 | /* |
414 | * open the device. Make sure the partition info is a up-to-date as can be. |
415 | */ |
416 | static int |
417 | sdopen(dev_t dev, int flag, int fmt, struct lwp *l) |
418 | { |
419 | struct sd_softc *sd; |
420 | struct scsipi_periph *periph; |
421 | struct scsipi_adapter *adapt; |
422 | int unit, part; |
423 | int error; |
424 | |
425 | unit = SDUNIT(dev); |
426 | sd = device_lookup_private(&sd_cd, unit); |
427 | if (sd == NULL) |
428 | return (ENXIO); |
429 | |
430 | if (!device_is_active(sd->sc_dev)) |
431 | return (ENODEV); |
432 | |
433 | part = SDPART(dev); |
434 | |
435 | mutex_enter(&sd->sc_dk.dk_openlock); |
436 | |
437 | /* |
438 | * If there are wedges, and this is not RAW_PART, then we |
439 | * need to fail. |
440 | */ |
441 | if (sd->sc_dk.dk_nwedges != 0 && part != RAW_PART) { |
442 | error = EBUSY; |
443 | goto bad1; |
444 | } |
445 | |
446 | periph = sd->sc_periph; |
447 | adapt = periph->periph_channel->chan_adapter; |
448 | |
449 | SC_DEBUG(periph, SCSIPI_DB1, |
450 | ("sdopen: dev=0x%" PRIx64" (unit %d (of %d), partition %d)\n" , dev, unit, |
451 | sd_cd.cd_ndevs, part)); |
452 | |
453 | /* |
454 | * If this is the first open of this device, add a reference |
455 | * to the adapter. |
456 | */ |
457 | if (sd->sc_dk.dk_openmask == 0 && |
458 | (error = scsipi_adapter_addref(adapt)) != 0) |
459 | goto bad1; |
460 | |
461 | if ((periph->periph_flags & PERIPH_OPEN) != 0) { |
462 | /* |
463 | * If any partition is open, but the disk has been invalidated, |
464 | * disallow further opens of non-raw partition |
465 | */ |
466 | if ((periph->periph_flags & PERIPH_MEDIA_LOADED) == 0 && |
467 | (part != RAW_PART || fmt != S_IFCHR)) { |
468 | error = EIO; |
469 | goto bad2; |
470 | } |
471 | } else { |
472 | int silent; |
473 | |
474 | if ((part == RAW_PART && fmt == S_IFCHR) || (flag & FSILENT)) |
475 | silent = XS_CTL_SILENT; |
476 | else |
477 | silent = 0; |
478 | |
479 | /* Check that it is still responding and ok. */ |
480 | error = scsipi_test_unit_ready(periph, |
481 | XS_CTL_IGNORE_ILLEGAL_REQUEST | XS_CTL_IGNORE_MEDIA_CHANGE | |
482 | silent); |
483 | |
484 | /* |
485 | * Start the pack spinning if necessary. Always allow the |
486 | * raw parition to be opened, for raw IOCTLs. Data transfers |
487 | * will check for SDEV_MEDIA_LOADED. |
488 | */ |
489 | if (error == EIO) { |
490 | int error2; |
491 | |
492 | error2 = scsipi_start(periph, SSS_START, silent); |
493 | switch (error2) { |
494 | case 0: |
495 | error = 0; |
496 | break; |
497 | case EIO: |
498 | case EINVAL: |
499 | break; |
500 | default: |
501 | error = error2; |
502 | break; |
503 | } |
504 | } |
505 | if (error) { |
506 | if (silent && (flag & FSILENT) == 0) |
507 | goto out; |
508 | goto bad2; |
509 | } |
510 | |
511 | periph->periph_flags |= PERIPH_OPEN; |
512 | |
513 | if (periph->periph_flags & PERIPH_REMOVABLE) { |
514 | /* Lock the pack in. */ |
515 | error = scsipi_prevent(periph, SPAMR_PREVENT_DT, |
516 | XS_CTL_IGNORE_ILLEGAL_REQUEST | |
517 | XS_CTL_IGNORE_MEDIA_CHANGE | |
518 | XS_CTL_SILENT); |
519 | if (error) |
520 | goto bad3; |
521 | } |
522 | |
523 | if ((periph->periph_flags & PERIPH_MEDIA_LOADED) == 0) { |
524 | int param_error; |
525 | periph->periph_flags |= PERIPH_MEDIA_LOADED; |
526 | |
527 | /* |
528 | * Load the physical device parameters. |
529 | * |
530 | * Note that if media is present but unformatted, |
531 | * we allow the open (so that it can be formatted!). |
532 | * The drive should refuse real I/O, if the media is |
533 | * unformatted. |
534 | */ |
535 | if ((param_error = sd_get_parms(sd, &sd->params, 0)) |
536 | == SDGP_RESULT_OFFLINE) { |
537 | error = ENXIO; |
538 | periph->periph_flags &= ~PERIPH_MEDIA_LOADED; |
539 | goto bad3; |
540 | } |
541 | SC_DEBUG(periph, SCSIPI_DB3, ("Params loaded " )); |
542 | |
543 | /* Load the partition info if not already loaded. */ |
544 | if (param_error == 0) { |
545 | if ((sdgetdisklabel(sd) != 0) && (part != RAW_PART)) { |
546 | error = EIO; |
547 | goto bad3; |
548 | } |
549 | SC_DEBUG(periph, SCSIPI_DB3, |
550 | ("Disklabel loaded " )); |
551 | } |
552 | } |
553 | } |
554 | |
555 | /* Check that the partition exists. */ |
556 | if (part != RAW_PART && |
557 | (part >= sd->sc_dk.dk_label->d_npartitions || |
558 | sd->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) { |
559 | error = ENXIO; |
560 | goto bad3; |
561 | } |
562 | |
563 | out: /* Insure only one open at a time. */ |
564 | switch (fmt) { |
565 | case S_IFCHR: |
566 | sd->sc_dk.dk_copenmask |= (1 << part); |
567 | break; |
568 | case S_IFBLK: |
569 | sd->sc_dk.dk_bopenmask |= (1 << part); |
570 | break; |
571 | } |
572 | sd->sc_dk.dk_openmask = |
573 | sd->sc_dk.dk_copenmask | sd->sc_dk.dk_bopenmask; |
574 | |
575 | SC_DEBUG(periph, SCSIPI_DB3, ("open complete\n" )); |
576 | mutex_exit(&sd->sc_dk.dk_openlock); |
577 | return (0); |
578 | |
579 | bad3: |
580 | if (sd->sc_dk.dk_openmask == 0) { |
581 | if (periph->periph_flags & PERIPH_REMOVABLE) |
582 | scsipi_prevent(periph, SPAMR_ALLOW, |
583 | XS_CTL_IGNORE_ILLEGAL_REQUEST | |
584 | XS_CTL_IGNORE_MEDIA_CHANGE | |
585 | XS_CTL_SILENT); |
586 | periph->periph_flags &= ~PERIPH_OPEN; |
587 | } |
588 | |
589 | bad2: |
590 | if (sd->sc_dk.dk_openmask == 0) |
591 | scsipi_adapter_delref(adapt); |
592 | |
593 | bad1: |
594 | mutex_exit(&sd->sc_dk.dk_openlock); |
595 | return (error); |
596 | } |
597 | |
598 | /* |
599 | * Caller must hold sd->sc_dk.dk_openlock. |
600 | */ |
601 | static int |
602 | sdlastclose(device_t self) |
603 | { |
604 | struct sd_softc *sd = device_private(self); |
605 | struct scsipi_periph *periph = sd->sc_periph; |
606 | struct scsipi_adapter *adapt = periph->periph_channel->chan_adapter; |
607 | |
608 | /* |
609 | * If the disk cache needs flushing, and the disk supports |
610 | * it, do it now. |
611 | */ |
612 | if ((sd->flags & SDF_DIRTY) != 0) { |
613 | if (sd_flush(sd, 0)) { |
614 | aprint_error_dev(sd->sc_dev, |
615 | "cache synchronization failed\n" ); |
616 | sd->flags &= ~SDF_FLUSHING; |
617 | } else |
618 | sd->flags &= ~(SDF_FLUSHING|SDF_DIRTY); |
619 | } |
620 | |
621 | scsipi_wait_drain(periph); |
622 | |
623 | if (periph->periph_flags & PERIPH_REMOVABLE) |
624 | scsipi_prevent(periph, SPAMR_ALLOW, |
625 | XS_CTL_IGNORE_ILLEGAL_REQUEST | |
626 | XS_CTL_IGNORE_NOT_READY | |
627 | XS_CTL_SILENT); |
628 | periph->periph_flags &= ~PERIPH_OPEN; |
629 | |
630 | scsipi_wait_drain(periph); |
631 | |
632 | scsipi_adapter_delref(adapt); |
633 | |
634 | return 0; |
635 | } |
636 | |
637 | /* |
638 | * close the device.. only called if we are the LAST occurence of an open |
639 | * device. Convenient now but usually a pain. |
640 | */ |
641 | static int |
642 | sdclose(dev_t dev, int flag, int fmt, struct lwp *l) |
643 | { |
644 | struct sd_softc *sd = device_lookup_private(&sd_cd, SDUNIT(dev)); |
645 | int part = SDPART(dev); |
646 | |
647 | mutex_enter(&sd->sc_dk.dk_openlock); |
648 | switch (fmt) { |
649 | case S_IFCHR: |
650 | sd->sc_dk.dk_copenmask &= ~(1 << part); |
651 | break; |
652 | case S_IFBLK: |
653 | sd->sc_dk.dk_bopenmask &= ~(1 << part); |
654 | break; |
655 | } |
656 | sd->sc_dk.dk_openmask = |
657 | sd->sc_dk.dk_copenmask | sd->sc_dk.dk_bopenmask; |
658 | |
659 | if (sd->sc_dk.dk_openmask == 0) |
660 | sdlastclose(sd->sc_dev); |
661 | |
662 | mutex_exit(&sd->sc_dk.dk_openlock); |
663 | return (0); |
664 | } |
665 | |
666 | /* |
667 | * Actually translate the requested transfer into one the physical driver |
668 | * can understand. The transfer is described by a buf and will include |
669 | * only one physical transfer. |
670 | */ |
671 | static void |
672 | sdstrategy(struct buf *bp) |
673 | { |
674 | struct sd_softc *sd = device_lookup_private(&sd_cd, SDUNIT(bp->b_dev)); |
675 | struct scsipi_periph *periph = sd->sc_periph; |
676 | struct scsipi_channel *chan = periph->periph_channel; |
677 | struct disklabel *lp; |
678 | daddr_t blkno; |
679 | bool sector_aligned; |
680 | |
681 | SC_DEBUG(sd->sc_periph, SCSIPI_DB2, ("sdstrategy " )); |
682 | SC_DEBUG(sd->sc_periph, SCSIPI_DB1, |
683 | ("%d bytes @ blk %" PRId64 "\n" , bp->b_bcount, bp->b_blkno)); |
684 | /* |
685 | * If the device has been made invalid, error out |
686 | */ |
687 | if ((periph->periph_flags & PERIPH_MEDIA_LOADED) == 0 || |
688 | !device_is_active(sd->sc_dev)) { |
689 | if (periph->periph_flags & PERIPH_OPEN) |
690 | bp->b_error = EIO; |
691 | else |
692 | bp->b_error = ENODEV; |
693 | goto done; |
694 | } |
695 | |
696 | lp = sd->sc_dk.dk_label; |
697 | |
698 | /* |
699 | * The transfer must be a whole number of blocks, offset must not be |
700 | * negative. |
701 | */ |
702 | if (lp->d_secsize == DEV_BSIZE) { |
703 | sector_aligned = (bp->b_bcount & (DEV_BSIZE - 1)) == 0; |
704 | } else { |
705 | sector_aligned = (bp->b_bcount % lp->d_secsize) == 0; |
706 | } |
707 | if (!sector_aligned || bp->b_blkno < 0) { |
708 | bp->b_error = EINVAL; |
709 | goto done; |
710 | } |
711 | /* |
712 | * If it's a null transfer, return immediatly |
713 | */ |
714 | if (bp->b_bcount == 0) |
715 | goto done; |
716 | |
717 | /* |
718 | * Do bounds checking, adjust transfer. if error, process. |
719 | * If end of partition, just return. |
720 | */ |
721 | if (SDPART(bp->b_dev) == RAW_PART) { |
722 | if (bounds_check_with_mediasize(bp, DEV_BSIZE, |
723 | sd->params.disksize512) <= 0) |
724 | goto done; |
725 | } else { |
726 | if (bounds_check_with_label(&sd->sc_dk, bp, |
727 | (sd->flags & (SDF_WLABEL|SDF_LABELLING)) != 0) <= 0) |
728 | goto done; |
729 | } |
730 | |
731 | /* |
732 | * Now convert the block number to absolute and put it in |
733 | * terms of the device's logical block size. |
734 | */ |
735 | if (lp->d_secsize == DEV_BSIZE) |
736 | blkno = bp->b_blkno; |
737 | else if (lp->d_secsize > DEV_BSIZE) |
738 | blkno = bp->b_blkno / (lp->d_secsize / DEV_BSIZE); |
739 | else |
740 | blkno = bp->b_blkno * (DEV_BSIZE / lp->d_secsize); |
741 | |
742 | if (SDPART(bp->b_dev) != RAW_PART) |
743 | blkno += lp->d_partitions[SDPART(bp->b_dev)].p_offset; |
744 | |
745 | bp->b_rawblkno = blkno; |
746 | |
747 | mutex_enter(chan_mtx(chan)); |
748 | |
749 | /* |
750 | * Place it in the queue of disk activities for this disk. |
751 | * |
752 | * XXX Only do disksort() if the current operating mode does not |
753 | * XXX include tagged queueing. |
754 | */ |
755 | bufq_put(sd->buf_queue, bp); |
756 | |
757 | /* |
758 | * Tell the device to get going on the transfer if it's |
759 | * not doing anything, otherwise just wait for completion |
760 | */ |
761 | sdstart(periph); |
762 | |
763 | mutex_exit(chan_mtx(chan)); |
764 | return; |
765 | |
766 | done: |
767 | /* |
768 | * Correctly set the buf to indicate a completed xfer |
769 | */ |
770 | bp->b_resid = bp->b_bcount; |
771 | biodone(bp); |
772 | } |
773 | |
774 | /* |
775 | * sdstart looks to see if there is a buf waiting for the device |
776 | * and that the device is not already busy. If both are true, |
777 | * It dequeues the buf and creates a scsi command to perform the |
778 | * transfer in the buf. The transfer request will call scsipi_done |
779 | * on completion, which will in turn call this routine again |
780 | * so that the next queued transfer is performed. |
781 | * The bufs are queued by the strategy routine (sdstrategy) |
782 | * |
783 | * This routine is also called after other non-queued requests |
784 | * have been made of the scsi driver, to ensure that the queue |
785 | * continues to be drained. |
786 | * |
787 | * must be called with channel lock held |
788 | * sdstart() is called from sdstrategy, sdrestart and scsipi_done |
789 | */ |
790 | static void |
791 | sdstart(struct scsipi_periph *periph) |
792 | { |
793 | struct sd_softc *sd = device_private(periph->periph_dev); |
794 | struct disklabel *lp = sd->sc_dk.dk_label; |
795 | struct buf *bp = 0; |
796 | struct scsipi_rw_16 cmd16; |
797 | struct scsipi_rw_10 cmd_big; |
798 | struct scsi_rw_6 cmd_small; |
799 | struct scsipi_generic *cmdp; |
800 | struct scsipi_xfer *xs; |
801 | int nblks, cmdlen, error __diagused, flags; |
802 | |
803 | SC_DEBUG(periph, SCSIPI_DB2, ("sdstart " )); |
804 | |
805 | /* |
806 | * Check if the device has room for another command |
807 | */ |
808 | while (periph->periph_active < periph->periph_openings) { |
809 | /* |
810 | * there is excess capacity, but a special waits |
811 | * It'll need the adapter as soon as we clear out of the |
812 | * way and let it run (user level wait). |
813 | */ |
814 | if (periph->periph_flags & PERIPH_WAITING) { |
815 | periph->periph_flags &= ~PERIPH_WAITING; |
816 | cv_broadcast(periph_cv_periph(periph)); |
817 | return; |
818 | } |
819 | |
820 | /* |
821 | * If the device has become invalid, abort all the |
822 | * reads and writes until all files have been closed and |
823 | * re-opened |
824 | */ |
825 | if (__predict_false( |
826 | (periph->periph_flags & PERIPH_MEDIA_LOADED) == 0)) { |
827 | if ((bp = bufq_get(sd->buf_queue)) != NULL) { |
828 | bp->b_error = EIO; |
829 | bp->b_resid = bp->b_bcount; |
830 | biodone(bp); |
831 | continue; |
832 | } else { |
833 | return; |
834 | } |
835 | } |
836 | |
837 | /* |
838 | * See if there is a buf with work for us to do.. |
839 | */ |
840 | if ((bp = bufq_peek(sd->buf_queue)) == NULL) |
841 | return; |
842 | |
843 | /* |
844 | * We have a buf, now we should make a command. |
845 | */ |
846 | |
847 | if (lp->d_secsize == DEV_BSIZE) |
848 | nblks = bp->b_bcount >> DEV_BSHIFT; |
849 | else |
850 | nblks = howmany(bp->b_bcount, lp->d_secsize); |
851 | |
852 | /* |
853 | * Fill out the scsi command. Use the smallest CDB possible |
854 | * (6-byte, 10-byte, or 16-byte). |
855 | */ |
856 | if (((bp->b_rawblkno & 0x1fffff) == bp->b_rawblkno) && |
857 | ((nblks & 0xff) == nblks) && |
858 | !(periph->periph_quirks & PQUIRK_ONLYBIG)) { |
859 | /* 6-byte CDB */ |
860 | memset(&cmd_small, 0, sizeof(cmd_small)); |
861 | cmd_small.opcode = (bp->b_flags & B_READ) ? |
862 | SCSI_READ_6_COMMAND : SCSI_WRITE_6_COMMAND; |
863 | _lto3b(bp->b_rawblkno, cmd_small.addr); |
864 | cmd_small.length = nblks & 0xff; |
865 | cmdlen = sizeof(cmd_small); |
866 | cmdp = (struct scsipi_generic *)&cmd_small; |
867 | } else if ((bp->b_rawblkno & 0xffffffff) == bp->b_rawblkno) { |
868 | /* 10-byte CDB */ |
869 | memset(&cmd_big, 0, sizeof(cmd_big)); |
870 | cmd_big.opcode = (bp->b_flags & B_READ) ? |
871 | READ_10 : WRITE_10; |
872 | _lto4b(bp->b_rawblkno, cmd_big.addr); |
873 | _lto2b(nblks, cmd_big.length); |
874 | cmdlen = sizeof(cmd_big); |
875 | cmdp = (struct scsipi_generic *)&cmd_big; |
876 | } else { |
877 | /* 16-byte CDB */ |
878 | memset(&cmd16, 0, sizeof(cmd16)); |
879 | cmd16.opcode = (bp->b_flags & B_READ) ? |
880 | READ_16 : WRITE_16; |
881 | _lto8b(bp->b_rawblkno, cmd16.addr); |
882 | _lto4b(nblks, cmd16.length); |
883 | cmdlen = sizeof(cmd16); |
884 | cmdp = (struct scsipi_generic *)&cmd16; |
885 | } |
886 | |
887 | /* Instrumentation. */ |
888 | disk_busy(&sd->sc_dk); |
889 | |
890 | /* |
891 | * Mark the disk dirty so that the cache will be |
892 | * flushed on close. |
893 | */ |
894 | if ((bp->b_flags & B_READ) == 0) |
895 | sd->flags |= SDF_DIRTY; |
896 | |
897 | /* |
898 | * Figure out what flags to use. |
899 | */ |
900 | flags = XS_CTL_NOSLEEP|XS_CTL_ASYNC|XS_CTL_SIMPLE_TAG; |
901 | if (bp->b_flags & B_READ) |
902 | flags |= XS_CTL_DATA_IN; |
903 | else |
904 | flags |= XS_CTL_DATA_OUT; |
905 | |
906 | /* |
907 | * Call the routine that chats with the adapter. |
908 | * Note: we cannot sleep as we may be an interrupt |
909 | */ |
910 | xs = scsipi_make_xs_locked(periph, cmdp, cmdlen, |
911 | (u_char *)bp->b_data, bp->b_bcount, |
912 | SDRETRIES, SD_IO_TIMEOUT, bp, flags); |
913 | if (__predict_false(xs == NULL)) { |
914 | /* |
915 | * out of memory. Keep this buffer in the queue, and |
916 | * retry later. |
917 | */ |
918 | callout_reset(&sd->sc_callout, hz / 2, sdrestart, |
919 | periph); |
920 | return; |
921 | } |
922 | /* |
923 | * need to dequeue the buffer before queuing the command, |
924 | * because cdstart may be called recursively from the |
925 | * HBA driver |
926 | */ |
927 | #ifdef DIAGNOSTIC |
928 | if (bufq_get(sd->buf_queue) != bp) |
929 | panic("sdstart(): dequeued wrong buf" ); |
930 | #else |
931 | bufq_get(sd->buf_queue); |
932 | #endif |
933 | error = scsipi_execute_xs(xs); |
934 | /* with a scsipi_xfer preallocated, scsipi_command can't fail */ |
935 | KASSERT(error == 0); |
936 | } |
937 | } |
938 | |
939 | static void |
940 | sdrestart(void *v) |
941 | { |
942 | struct scsipi_periph *periph = v; |
943 | struct scsipi_channel *chan = periph->periph_channel; |
944 | |
945 | mutex_enter(chan_mtx(chan)); |
946 | sdstart((struct scsipi_periph *)v); |
947 | mutex_exit(chan_mtx(chan)); |
948 | } |
949 | |
950 | static void |
951 | sddone(struct scsipi_xfer *xs, int error) |
952 | { |
953 | struct sd_softc *sd = device_private(xs->xs_periph->periph_dev); |
954 | struct buf *bp = xs->bp; |
955 | |
956 | if (sd->flags & SDF_FLUSHING) { |
957 | /* Flush completed, no longer dirty. */ |
958 | sd->flags &= ~(SDF_FLUSHING|SDF_DIRTY); |
959 | } |
960 | |
961 | if (bp) { |
962 | bp->b_error = error; |
963 | bp->b_resid = xs->resid; |
964 | if (error) { |
965 | /* on a read/write error bp->b_resid is zero, so fix */ |
966 | bp->b_resid = bp->b_bcount; |
967 | } |
968 | |
969 | disk_unbusy(&sd->sc_dk, bp->b_bcount - bp->b_resid, |
970 | (bp->b_flags & B_READ)); |
971 | rnd_add_uint32(&sd->rnd_source, bp->b_rawblkno); |
972 | |
973 | biodone(bp); |
974 | } |
975 | } |
976 | |
977 | static void |
978 | sdminphys(struct buf *bp) |
979 | { |
980 | struct sd_softc *sd = device_lookup_private(&sd_cd, SDUNIT(bp->b_dev)); |
981 | long xmax; |
982 | |
983 | /* |
984 | * If the device is ancient, we want to make sure that |
985 | * the transfer fits into a 6-byte cdb. |
986 | * |
987 | * XXX Note that the SCSI-I spec says that 256-block transfers |
988 | * are allowed in a 6-byte read/write, and are specified |
989 | * by settng the "length" to 0. However, we're conservative |
990 | * here, allowing only 255-block transfers in case an |
991 | * ancient device gets confused by length == 0. A length of 0 |
992 | * in a 10-byte read/write actually means 0 blocks. |
993 | */ |
994 | if ((sd->flags & SDF_ANCIENT) && |
995 | ((sd->sc_periph->periph_flags & |
996 | (PERIPH_REMOVABLE | PERIPH_MEDIA_LOADED)) != PERIPH_REMOVABLE)) { |
997 | xmax = sd->sc_dk.dk_label->d_secsize * 0xff; |
998 | |
999 | if (bp->b_bcount > xmax) |
1000 | bp->b_bcount = xmax; |
1001 | } |
1002 | |
1003 | scsipi_adapter_minphys(sd->sc_periph->periph_channel, bp); |
1004 | } |
1005 | |
1006 | static int |
1007 | sdread(dev_t dev, struct uio *uio, int ioflag) |
1008 | { |
1009 | |
1010 | return (physio(sdstrategy, NULL, dev, B_READ, sdminphys, uio)); |
1011 | } |
1012 | |
1013 | static int |
1014 | sdwrite(dev_t dev, struct uio *uio, int ioflag) |
1015 | { |
1016 | |
1017 | return (physio(sdstrategy, NULL, dev, B_WRITE, sdminphys, uio)); |
1018 | } |
1019 | |
1020 | /* |
1021 | * Perform special action on behalf of the user |
1022 | * Knows about the internals of this device |
1023 | */ |
1024 | static int |
1025 | sdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l) |
1026 | { |
1027 | struct sd_softc *sd = device_lookup_private(&sd_cd, SDUNIT(dev)); |
1028 | struct scsipi_periph *periph = sd->sc_periph; |
1029 | int part = SDPART(dev); |
1030 | int error; |
1031 | #ifdef __HAVE_OLD_DISKLABEL |
1032 | struct disklabel *newlabel = NULL; |
1033 | #endif |
1034 | |
1035 | SC_DEBUG(sd->sc_periph, SCSIPI_DB2, ("sdioctl 0x%lx " , cmd)); |
1036 | |
1037 | /* |
1038 | * If the device is not valid, some IOCTLs can still be |
1039 | * handled on the raw partition. Check this here. |
1040 | */ |
1041 | if ((periph->periph_flags & PERIPH_MEDIA_LOADED) == 0) { |
1042 | switch (cmd) { |
1043 | case DIOCKLABEL: |
1044 | case DIOCWLABEL: |
1045 | case DIOCLOCK: |
1046 | case DIOCEJECT: |
1047 | case ODIOCEJECT: |
1048 | case DIOCGCACHE: |
1049 | case DIOCSCACHE: |
1050 | case DIOCGSTRATEGY: |
1051 | case DIOCSSTRATEGY: |
1052 | case SCIOCIDENTIFY: |
1053 | case OSCIOCIDENTIFY: |
1054 | case SCIOCCOMMAND: |
1055 | case SCIOCDEBUG: |
1056 | if (part == RAW_PART) |
1057 | break; |
1058 | /* FALLTHROUGH */ |
1059 | default: |
1060 | if ((periph->periph_flags & PERIPH_OPEN) == 0) |
1061 | return (ENODEV); |
1062 | else |
1063 | return (EIO); |
1064 | } |
1065 | } |
1066 | |
1067 | error = disk_ioctl(&sd->sc_dk, dev, cmd, addr, flag, l); |
1068 | if (error != EPASSTHROUGH) |
1069 | return (error); |
1070 | |
1071 | error = 0; |
1072 | switch (cmd) { |
1073 | case DIOCWDINFO: |
1074 | case DIOCSDINFO: |
1075 | #ifdef __HAVE_OLD_DISKLABEL |
1076 | case ODIOCWDINFO: |
1077 | case ODIOCSDINFO: |
1078 | #endif |
1079 | { |
1080 | struct disklabel *lp; |
1081 | |
1082 | if ((flag & FWRITE) == 0) |
1083 | return (EBADF); |
1084 | |
1085 | #ifdef __HAVE_OLD_DISKLABEL |
1086 | if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) { |
1087 | newlabel = malloc(sizeof *newlabel, M_TEMP, |
1088 | M_WAITOK | M_ZERO); |
1089 | if (newlabel == NULL) |
1090 | return EIO; |
1091 | memcpy(newlabel, addr, sizeof (struct olddisklabel)); |
1092 | lp = newlabel; |
1093 | } else |
1094 | #endif |
1095 | lp = (struct disklabel *)addr; |
1096 | |
1097 | mutex_enter(&sd->sc_dk.dk_openlock); |
1098 | sd->flags |= SDF_LABELLING; |
1099 | |
1100 | error = setdisklabel(sd->sc_dk.dk_label, |
1101 | lp, /*sd->sc_dk.dk_openmask : */0, |
1102 | sd->sc_dk.dk_cpulabel); |
1103 | if (error == 0) { |
1104 | if (cmd == DIOCWDINFO |
1105 | #ifdef __HAVE_OLD_DISKLABEL |
1106 | || cmd == ODIOCWDINFO |
1107 | #endif |
1108 | ) |
1109 | error = writedisklabel(SDLABELDEV(dev), |
1110 | sdstrategy, sd->sc_dk.dk_label, |
1111 | sd->sc_dk.dk_cpulabel); |
1112 | } |
1113 | |
1114 | sd->flags &= ~SDF_LABELLING; |
1115 | mutex_exit(&sd->sc_dk.dk_openlock); |
1116 | #ifdef __HAVE_OLD_DISKLABEL |
1117 | if (newlabel != NULL) |
1118 | free(newlabel, M_TEMP); |
1119 | #endif |
1120 | return (error); |
1121 | } |
1122 | |
1123 | case DIOCKLABEL: |
1124 | if (*(int *)addr) |
1125 | periph->periph_flags |= PERIPH_KEEP_LABEL; |
1126 | else |
1127 | periph->periph_flags &= ~PERIPH_KEEP_LABEL; |
1128 | return (0); |
1129 | |
1130 | case DIOCWLABEL: |
1131 | if ((flag & FWRITE) == 0) |
1132 | return (EBADF); |
1133 | if (*(int *)addr) |
1134 | sd->flags |= SDF_WLABEL; |
1135 | else |
1136 | sd->flags &= ~SDF_WLABEL; |
1137 | return (0); |
1138 | |
1139 | case DIOCLOCK: |
1140 | if (periph->periph_flags & PERIPH_REMOVABLE) |
1141 | return (scsipi_prevent(periph, |
1142 | (*(int *)addr) ? |
1143 | SPAMR_PREVENT_DT : SPAMR_ALLOW, 0)); |
1144 | else |
1145 | return (ENOTTY); |
1146 | |
1147 | case DIOCEJECT: |
1148 | if ((periph->periph_flags & PERIPH_REMOVABLE) == 0) |
1149 | return (ENOTTY); |
1150 | if (*(int *)addr == 0) { |
1151 | /* |
1152 | * Don't force eject: check that we are the only |
1153 | * partition open. If so, unlock it. |
1154 | */ |
1155 | if ((sd->sc_dk.dk_openmask & ~(1 << part)) == 0 && |
1156 | sd->sc_dk.dk_bopenmask + sd->sc_dk.dk_copenmask == |
1157 | sd->sc_dk.dk_openmask) { |
1158 | error = scsipi_prevent(periph, SPAMR_ALLOW, |
1159 | XS_CTL_IGNORE_NOT_READY); |
1160 | if (error) |
1161 | return (error); |
1162 | } else { |
1163 | return (EBUSY); |
1164 | } |
1165 | } |
1166 | /* FALLTHROUGH */ |
1167 | case ODIOCEJECT: |
1168 | return ((periph->periph_flags & PERIPH_REMOVABLE) == 0 ? |
1169 | ENOTTY : scsipi_start(periph, SSS_STOP|SSS_LOEJ, 0)); |
1170 | |
1171 | case DIOCGDEFLABEL: |
1172 | sdgetdefaultlabel(sd, (struct disklabel *)addr); |
1173 | return (0); |
1174 | |
1175 | #ifdef __HAVE_OLD_DISKLABEL |
1176 | case ODIOCGDEFLABEL: |
1177 | newlabel = malloc(sizeof *newlabel, M_TEMP, M_WAITOK); |
1178 | if (newlabel == NULL) |
1179 | return EIO; |
1180 | sdgetdefaultlabel(sd, newlabel); |
1181 | if (newlabel->d_npartitions <= OLDMAXPARTITIONS) |
1182 | memcpy(addr, newlabel, sizeof (struct olddisklabel)); |
1183 | else |
1184 | error = ENOTTY; |
1185 | free(newlabel, M_TEMP); |
1186 | return error; |
1187 | #endif |
1188 | |
1189 | case DIOCGCACHE: |
1190 | return (sd_getcache(sd, (int *) addr)); |
1191 | |
1192 | case DIOCSCACHE: |
1193 | if ((flag & FWRITE) == 0) |
1194 | return (EBADF); |
1195 | return (sd_setcache(sd, *(int *) addr)); |
1196 | |
1197 | case DIOCCACHESYNC: |
1198 | /* |
1199 | * XXX Do we really need to care about having a writable |
1200 | * file descriptor here? |
1201 | */ |
1202 | if ((flag & FWRITE) == 0) |
1203 | return (EBADF); |
1204 | if (((sd->flags & SDF_DIRTY) != 0 || *(int *)addr != 0)) { |
1205 | error = sd_flush(sd, 0); |
1206 | if (error) |
1207 | sd->flags &= ~SDF_FLUSHING; |
1208 | else |
1209 | sd->flags &= ~(SDF_FLUSHING|SDF_DIRTY); |
1210 | } |
1211 | return (error); |
1212 | |
1213 | case DIOCGSTRATEGY: |
1214 | { |
1215 | struct disk_strategy *dks = addr; |
1216 | int s; |
1217 | |
1218 | s = splbio(); |
1219 | strlcpy(dks->dks_name, bufq_getstrategyname(sd->buf_queue), |
1220 | sizeof(dks->dks_name)); |
1221 | splx(s); |
1222 | dks->dks_paramlen = 0; |
1223 | |
1224 | return 0; |
1225 | } |
1226 | |
1227 | case DIOCSSTRATEGY: |
1228 | { |
1229 | struct disk_strategy *dks = addr; |
1230 | struct bufq_state *new_bufq; |
1231 | struct bufq_state *old_bufq; |
1232 | int s; |
1233 | |
1234 | if ((flag & FWRITE) == 0) { |
1235 | return EBADF; |
1236 | } |
1237 | |
1238 | if (dks->dks_param != NULL) { |
1239 | return EINVAL; |
1240 | } |
1241 | dks->dks_name[sizeof(dks->dks_name) - 1] = 0; /* ensure term */ |
1242 | error = bufq_alloc(&new_bufq, dks->dks_name, |
1243 | BUFQ_EXACT|BUFQ_SORT_RAWBLOCK); |
1244 | if (error) { |
1245 | return error; |
1246 | } |
1247 | s = splbio(); |
1248 | old_bufq = sd->buf_queue; |
1249 | bufq_move(new_bufq, old_bufq); |
1250 | sd->buf_queue = new_bufq; |
1251 | splx(s); |
1252 | bufq_free(old_bufq); |
1253 | |
1254 | return 0; |
1255 | } |
1256 | |
1257 | default: |
1258 | if (part != RAW_PART) |
1259 | return (ENOTTY); |
1260 | return (scsipi_do_ioctl(periph, dev, cmd, addr, flag, l)); |
1261 | } |
1262 | |
1263 | #ifdef DIAGNOSTIC |
1264 | panic("sdioctl: impossible" ); |
1265 | #endif |
1266 | } |
1267 | |
1268 | static void |
1269 | sdgetdefaultlabel(struct sd_softc *sd, struct disklabel *lp) |
1270 | { |
1271 | |
1272 | memset(lp, 0, sizeof(struct disklabel)); |
1273 | |
1274 | lp->d_secsize = sd->params.blksize; |
1275 | lp->d_ntracks = sd->params.heads; |
1276 | lp->d_nsectors = sd->params.sectors; |
1277 | lp->d_ncylinders = sd->params.cyls; |
1278 | lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; |
1279 | |
1280 | switch (SCSIPI_BUSTYPE_TYPE(scsipi_periph_bustype(sd->sc_periph))) { |
1281 | case SCSIPI_BUSTYPE_SCSI: |
1282 | lp->d_type = DKTYPE_SCSI; |
1283 | break; |
1284 | case SCSIPI_BUSTYPE_ATAPI: |
1285 | lp->d_type = DKTYPE_ATAPI; |
1286 | break; |
1287 | } |
1288 | /* |
1289 | * XXX |
1290 | * We could probe the mode pages to figure out what kind of disc it is. |
1291 | * Is this worthwhile? |
1292 | */ |
1293 | strncpy(lp->d_typename, sd->name, 16); |
1294 | strncpy(lp->d_packname, "fictitious" , 16); |
1295 | if (sd->params.disksize > UINT32_MAX) |
1296 | lp->d_secperunit = UINT32_MAX; |
1297 | else |
1298 | lp->d_secperunit = sd->params.disksize; |
1299 | lp->d_rpm = sd->params.rot_rate; |
1300 | lp->d_interleave = 1; |
1301 | lp->d_flags = sd->sc_periph->periph_flags & PERIPH_REMOVABLE ? |
1302 | D_REMOVABLE : 0; |
1303 | |
1304 | lp->d_partitions[RAW_PART].p_offset = 0; |
1305 | lp->d_partitions[RAW_PART].p_size = lp->d_secperunit; |
1306 | lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED; |
1307 | lp->d_npartitions = RAW_PART + 1; |
1308 | |
1309 | lp->d_magic = DISKMAGIC; |
1310 | lp->d_magic2 = DISKMAGIC; |
1311 | lp->d_checksum = dkcksum(lp); |
1312 | } |
1313 | |
1314 | |
1315 | /* |
1316 | * Load the label information on the named device |
1317 | */ |
1318 | static int |
1319 | sdgetdisklabel(struct sd_softc *sd) |
1320 | { |
1321 | struct disklabel *lp = sd->sc_dk.dk_label; |
1322 | const char *errstring; |
1323 | |
1324 | memset(sd->sc_dk.dk_cpulabel, 0, sizeof(struct cpu_disklabel)); |
1325 | |
1326 | sdgetdefaultlabel(sd, lp); |
1327 | |
1328 | if (lp->d_secpercyl == 0) { |
1329 | lp->d_secpercyl = 100; |
1330 | /* as long as it's not 0 - readdisklabel divides by it (?) */ |
1331 | } |
1332 | |
1333 | /* |
1334 | * Call the generic disklabel extraction routine |
1335 | */ |
1336 | errstring = readdisklabel(MAKESDDEV(0, device_unit(sd->sc_dev), |
1337 | RAW_PART), sdstrategy, lp, sd->sc_dk.dk_cpulabel); |
1338 | if (errstring) { |
1339 | aprint_error_dev(sd->sc_dev, "%s\n" , errstring); |
1340 | return EIO; |
1341 | } |
1342 | return 0; |
1343 | } |
1344 | |
1345 | static bool |
1346 | sd_shutdown(device_t self, int how) |
1347 | { |
1348 | struct sd_softc *sd = device_private(self); |
1349 | |
1350 | /* |
1351 | * If the disk cache needs to be flushed, and the disk supports |
1352 | * it, flush it. We're cold at this point, so we poll for |
1353 | * completion. |
1354 | */ |
1355 | if ((sd->flags & SDF_DIRTY) != 0) { |
1356 | if (sd_flush(sd, XS_CTL_NOSLEEP|XS_CTL_POLL)) { |
1357 | aprint_error_dev(sd->sc_dev, |
1358 | "cache synchronization failed\n" ); |
1359 | sd->flags &= ~SDF_FLUSHING; |
1360 | } else |
1361 | sd->flags &= ~(SDF_FLUSHING|SDF_DIRTY); |
1362 | } |
1363 | return true; |
1364 | } |
1365 | |
1366 | static bool |
1367 | sd_suspend(device_t dv, const pmf_qual_t *qual) |
1368 | { |
1369 | return sd_shutdown(dv, boothowto); /* XXX no need to poll */ |
1370 | } |
1371 | |
1372 | /* |
1373 | * Check Errors |
1374 | */ |
1375 | static int |
1376 | sd_interpret_sense(struct scsipi_xfer *xs) |
1377 | { |
1378 | struct scsipi_periph *periph = xs->xs_periph; |
1379 | struct scsipi_channel *chan = periph->periph_channel; |
1380 | struct scsi_sense_data *sense = &xs->sense.scsi_sense; |
1381 | struct sd_softc *sd = device_private(periph->periph_dev); |
1382 | int error, retval = EJUSTRETURN; |
1383 | |
1384 | /* |
1385 | * If the periph is already recovering, just do the normal |
1386 | * error processing. |
1387 | */ |
1388 | if (periph->periph_flags & PERIPH_RECOVERING) |
1389 | return (retval); |
1390 | |
1391 | /* |
1392 | * Ignore errors from accessing illegal fields (e.g. trying to |
1393 | * lock the door of a digicam, which doesn't have a door that |
1394 | * can be locked) for the SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL command. |
1395 | */ |
1396 | if (xs->cmd->opcode == SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL && |
1397 | SSD_SENSE_KEY(sense->flags) == SKEY_ILLEGAL_REQUEST && |
1398 | sense->asc == 0x24 && |
1399 | sense->ascq == 0x00) { /* Illegal field in CDB */ |
1400 | if (!(xs->xs_control & XS_CTL_SILENT)) { |
1401 | scsipi_printaddr(periph); |
1402 | printf("no door lock\n" ); |
1403 | } |
1404 | xs->xs_control |= XS_CTL_IGNORE_ILLEGAL_REQUEST; |
1405 | return (retval); |
1406 | } |
1407 | |
1408 | |
1409 | |
1410 | /* |
1411 | * If the device is not open yet, let the generic code handle it. |
1412 | */ |
1413 | if ((periph->periph_flags & PERIPH_MEDIA_LOADED) == 0) |
1414 | return (retval); |
1415 | |
1416 | /* |
1417 | * If it isn't a extended or extended/deferred error, let |
1418 | * the generic code handle it. |
1419 | */ |
1420 | if (SSD_RCODE(sense->response_code) != SSD_RCODE_CURRENT && |
1421 | SSD_RCODE(sense->response_code) != SSD_RCODE_DEFERRED) |
1422 | return (retval); |
1423 | |
1424 | if (SSD_SENSE_KEY(sense->flags) == SKEY_NOT_READY && |
1425 | sense->asc == 0x4) { |
1426 | if (sense->ascq == 0x01) { |
1427 | /* |
1428 | * Unit In The Process Of Becoming Ready. |
1429 | */ |
1430 | printf("%s: waiting for pack to spin up...\n" , |
1431 | device_xname(sd->sc_dev)); |
1432 | if (!callout_pending(&periph->periph_callout)) |
1433 | scsipi_periph_freeze(periph, 1); |
1434 | callout_reset(&periph->periph_callout, |
1435 | 5 * hz, scsipi_periph_timed_thaw, periph); |
1436 | retval = ERESTART; |
1437 | } else if (sense->ascq == 0x02) { |
1438 | printf("%s: pack is stopped, restarting...\n" , |
1439 | device_xname(sd->sc_dev)); |
1440 | mutex_enter(chan_mtx(chan)); |
1441 | periph->periph_flags |= PERIPH_RECOVERING; |
1442 | mutex_exit(chan_mtx(chan)); |
1443 | error = scsipi_start(periph, SSS_START, |
1444 | XS_CTL_URGENT|XS_CTL_HEAD_TAG| |
1445 | XS_CTL_THAW_PERIPH|XS_CTL_FREEZE_PERIPH); |
1446 | if (error) { |
1447 | aprint_error_dev(sd->sc_dev, |
1448 | "unable to restart pack\n" ); |
1449 | retval = error; |
1450 | } else |
1451 | retval = ERESTART; |
1452 | mutex_enter(chan_mtx(chan)); |
1453 | periph->periph_flags &= ~PERIPH_RECOVERING; |
1454 | mutex_exit(chan_mtx(chan)); |
1455 | } |
1456 | } |
1457 | if (SSD_SENSE_KEY(sense->flags) == SKEY_MEDIUM_ERROR && |
1458 | sense->asc == 0x31 && |
1459 | sense->ascq == 0x00) { /* maybe for any asq ? */ |
1460 | /* Medium Format Corrupted */ |
1461 | retval = EFTYPE; |
1462 | } |
1463 | return (retval); |
1464 | } |
1465 | |
1466 | |
1467 | static int |
1468 | sdsize(dev_t dev) |
1469 | { |
1470 | struct sd_softc *sd; |
1471 | int part, unit, omask; |
1472 | int size; |
1473 | |
1474 | unit = SDUNIT(dev); |
1475 | sd = device_lookup_private(&sd_cd, unit); |
1476 | if (sd == NULL) |
1477 | return (-1); |
1478 | |
1479 | if (!device_is_active(sd->sc_dev)) |
1480 | return (-1); |
1481 | |
1482 | part = SDPART(dev); |
1483 | omask = sd->sc_dk.dk_openmask & (1 << part); |
1484 | |
1485 | if (omask == 0 && sdopen(dev, 0, S_IFBLK, NULL) != 0) |
1486 | return (-1); |
1487 | if ((sd->sc_periph->periph_flags & PERIPH_MEDIA_LOADED) == 0) |
1488 | size = -1; |
1489 | else if (sd->sc_dk.dk_label->d_partitions[part].p_fstype != FS_SWAP) |
1490 | size = -1; |
1491 | else |
1492 | size = sd->sc_dk.dk_label->d_partitions[part].p_size * |
1493 | (sd->sc_dk.dk_label->d_secsize / DEV_BSIZE); |
1494 | if (omask == 0 && sdclose(dev, 0, S_IFBLK, NULL) != 0) |
1495 | return (-1); |
1496 | return (size); |
1497 | } |
1498 | |
1499 | /* #define SD_DUMP_NOT_TRUSTED if you just want to watch */ |
1500 | static struct scsipi_xfer sx; |
1501 | static int sddoingadump; |
1502 | |
1503 | /* |
1504 | * dump all of physical memory into the partition specified, starting |
1505 | * at offset 'dumplo' into the partition. |
1506 | */ |
1507 | static int |
1508 | sddump(dev_t dev, daddr_t blkno, void *va, size_t size) |
1509 | { |
1510 | struct sd_softc *sd; /* disk unit to do the I/O */ |
1511 | struct disklabel *lp; /* disk's disklabel */ |
1512 | int unit, part; |
1513 | int sectorsize; /* size of a disk sector */ |
1514 | int nsects; /* number of sectors in partition */ |
1515 | int sectoff; /* sector offset of partition */ |
1516 | int totwrt; /* total number of sectors left to write */ |
1517 | int nwrt; /* current number of sectors to write */ |
1518 | struct scsipi_rw_10 cmd; /* write command */ |
1519 | struct scsipi_xfer *xs; /* ... convenience */ |
1520 | struct scsipi_periph *periph; |
1521 | struct scsipi_channel *chan; |
1522 | |
1523 | /* Check if recursive dump; if so, punt. */ |
1524 | if (sddoingadump) |
1525 | return (EFAULT); |
1526 | |
1527 | /* Mark as active early. */ |
1528 | sddoingadump = 1; |
1529 | |
1530 | unit = SDUNIT(dev); /* Decompose unit & partition. */ |
1531 | part = SDPART(dev); |
1532 | |
1533 | /* Check for acceptable drive number. */ |
1534 | sd = device_lookup_private(&sd_cd, unit); |
1535 | if (sd == NULL) |
1536 | return (ENXIO); |
1537 | |
1538 | if (!device_is_active(sd->sc_dev)) |
1539 | return (ENODEV); |
1540 | |
1541 | periph = sd->sc_periph; |
1542 | chan = periph->periph_channel; |
1543 | |
1544 | /* Make sure it was initialized. */ |
1545 | if ((periph->periph_flags & PERIPH_MEDIA_LOADED) == 0) |
1546 | return (ENXIO); |
1547 | |
1548 | /* Convert to disk sectors. Request must be a multiple of size. */ |
1549 | lp = sd->sc_dk.dk_label; |
1550 | sectorsize = lp->d_secsize; |
1551 | if ((size % sectorsize) != 0) |
1552 | return (EFAULT); |
1553 | totwrt = size / sectorsize; |
1554 | blkno = dbtob(blkno) / sectorsize; /* blkno in DEV_BSIZE units */ |
1555 | |
1556 | nsects = lp->d_partitions[part].p_size; |
1557 | sectoff = lp->d_partitions[part].p_offset; |
1558 | |
1559 | /* Check transfer bounds against partition size. */ |
1560 | if ((blkno < 0) || ((blkno + totwrt) > nsects)) |
1561 | return (EINVAL); |
1562 | |
1563 | /* Offset block number to start of partition. */ |
1564 | blkno += sectoff; |
1565 | |
1566 | xs = &sx; |
1567 | |
1568 | while (totwrt > 0) { |
1569 | nwrt = totwrt; /* XXX */ |
1570 | #ifndef SD_DUMP_NOT_TRUSTED |
1571 | /* |
1572 | * Fill out the scsi command |
1573 | */ |
1574 | memset(&cmd, 0, sizeof(cmd)); |
1575 | cmd.opcode = WRITE_10; |
1576 | _lto4b(blkno, cmd.addr); |
1577 | _lto2b(nwrt, cmd.length); |
1578 | /* |
1579 | * Fill out the scsipi_xfer structure |
1580 | * Note: we cannot sleep as we may be an interrupt |
1581 | * don't use scsipi_command() as it may want to wait |
1582 | * for an xs. |
1583 | */ |
1584 | memset(xs, 0, sizeof(sx)); |
1585 | xs->xs_control |= XS_CTL_NOSLEEP | XS_CTL_POLL | |
1586 | XS_CTL_DATA_OUT; |
1587 | xs->xs_status = 0; |
1588 | xs->xs_periph = periph; |
1589 | xs->xs_retries = SDRETRIES; |
1590 | xs->timeout = 10000; /* 10000 millisecs for a disk ! */ |
1591 | xs->cmd = (struct scsipi_generic *)&cmd; |
1592 | xs->cmdlen = sizeof(cmd); |
1593 | xs->resid = nwrt * sectorsize; |
1594 | xs->error = XS_NOERROR; |
1595 | xs->bp = 0; |
1596 | xs->data = va; |
1597 | xs->datalen = nwrt * sectorsize; |
1598 | callout_init(&xs->xs_callout, 0); |
1599 | |
1600 | /* |
1601 | * Pass all this info to the scsi driver. |
1602 | */ |
1603 | scsipi_adapter_request(chan, ADAPTER_REQ_RUN_XFER, xs); |
1604 | if ((xs->xs_status & XS_STS_DONE) == 0 || |
1605 | xs->error != XS_NOERROR) |
1606 | return (EIO); |
1607 | #else /* SD_DUMP_NOT_TRUSTED */ |
1608 | /* Let's just talk about this first... */ |
1609 | printf("sd%d: dump addr 0x%x, blk %d\n" , unit, va, blkno); |
1610 | delay(500 * 1000); /* half a second */ |
1611 | #endif /* SD_DUMP_NOT_TRUSTED */ |
1612 | |
1613 | /* update block count */ |
1614 | totwrt -= nwrt; |
1615 | blkno += nwrt; |
1616 | va = (char *)va + sectorsize * nwrt; |
1617 | } |
1618 | sddoingadump = 0; |
1619 | return (0); |
1620 | } |
1621 | |
1622 | static int |
1623 | sd_mode_sense(struct sd_softc *sd, u_int8_t byte2, void *sense, size_t size, |
1624 | int page, int flags, int *big) |
1625 | { |
1626 | |
1627 | if ((sd->sc_periph->periph_quirks & PQUIRK_ONLYBIG) && |
1628 | !(sd->sc_periph->periph_quirks & PQUIRK_NOBIGMODESENSE)) { |
1629 | *big = 1; |
1630 | return scsipi_mode_sense_big(sd->sc_periph, byte2, page, sense, |
1631 | size + sizeof(struct scsi_mode_parameter_header_10), |
1632 | flags, SDRETRIES, 6000); |
1633 | } else { |
1634 | *big = 0; |
1635 | return scsipi_mode_sense(sd->sc_periph, byte2, page, sense, |
1636 | size + sizeof(struct scsi_mode_parameter_header_6), |
1637 | flags, SDRETRIES, 6000); |
1638 | } |
1639 | } |
1640 | |
1641 | static int |
1642 | sd_mode_select(struct sd_softc *sd, u_int8_t byte2, void *sense, size_t size, |
1643 | int flags, int big) |
1644 | { |
1645 | |
1646 | if (big) { |
1647 | struct scsi_mode_parameter_header_10 * = sense; |
1648 | |
1649 | _lto2b(0, header->data_length); |
1650 | return scsipi_mode_select_big(sd->sc_periph, byte2, sense, |
1651 | size + sizeof(struct scsi_mode_parameter_header_10), |
1652 | flags, SDRETRIES, 6000); |
1653 | } else { |
1654 | struct scsi_mode_parameter_header_6 * = sense; |
1655 | |
1656 | header->data_length = 0; |
1657 | return scsipi_mode_select(sd->sc_periph, byte2, sense, |
1658 | size + sizeof(struct scsi_mode_parameter_header_6), |
1659 | flags, SDRETRIES, 6000); |
1660 | } |
1661 | } |
1662 | |
1663 | /* |
1664 | * sd_validate_blksize: |
1665 | * |
1666 | * Validate the block size. Print error if periph is specified, |
1667 | */ |
1668 | static int |
1669 | sd_validate_blksize(struct scsipi_periph *periph, int len) |
1670 | { |
1671 | |
1672 | switch (len) { |
1673 | case 256: |
1674 | case 512: |
1675 | case 1024: |
1676 | case 2048: |
1677 | case 4096: |
1678 | return 1; |
1679 | } |
1680 | |
1681 | if (periph) { |
1682 | scsipi_printaddr(periph); |
1683 | printf("%s sector size: 0x%x. Defaulting to %d bytes.\n" , |
1684 | (len ^ (1 << (ffs(len) - 1))) ? |
1685 | "preposterous" : "unsupported" , |
1686 | len, SD_DEFAULT_BLKSIZE); |
1687 | } |
1688 | |
1689 | return 0; |
1690 | } |
1691 | |
1692 | /* |
1693 | * sd_read_capacity: |
1694 | * |
1695 | * Find out from the device what its capacity is. |
1696 | */ |
1697 | static u_int64_t |
1698 | sd_read_capacity(struct scsipi_periph *periph, int *blksize, int flags) |
1699 | { |
1700 | union { |
1701 | struct scsipi_read_capacity_10 cmd; |
1702 | struct scsipi_read_capacity_16 cmd16; |
1703 | } cmd; |
1704 | union { |
1705 | struct scsipi_read_capacity_10_data data; |
1706 | struct scsipi_read_capacity_16_data data16; |
1707 | } *datap; |
1708 | uint64_t rv; |
1709 | |
1710 | memset(&cmd, 0, sizeof(cmd)); |
1711 | cmd.cmd.opcode = READ_CAPACITY_10; |
1712 | |
1713 | /* |
1714 | * Don't allocate data buffer on stack; |
1715 | * The lower driver layer might use the same stack and |
1716 | * if it uses region which is in the same cacheline, |
1717 | * cache flush ops against the data buffer won't work properly. |
1718 | */ |
1719 | datap = malloc(sizeof(*datap), M_TEMP, M_WAITOK); |
1720 | if (datap == NULL) |
1721 | return 0; |
1722 | |
1723 | /* |
1724 | * If the command works, interpret the result as a 4 byte |
1725 | * number of blocks |
1726 | */ |
1727 | rv = 0; |
1728 | memset(datap, 0, sizeof(datap->data)); |
1729 | if (scsipi_command(periph, (void *)&cmd.cmd, sizeof(cmd.cmd), |
1730 | (void *)datap, sizeof(datap->data), SCSIPIRETRIES, 20000, NULL, |
1731 | flags | XS_CTL_DATA_IN | XS_CTL_SILENT) != 0) |
1732 | goto out; |
1733 | |
1734 | if (_4btol(datap->data.addr) != 0xffffffff) { |
1735 | *blksize = _4btol(datap->data.length); |
1736 | rv = _4btol(datap->data.addr) + 1; |
1737 | goto out; |
1738 | } |
1739 | |
1740 | /* |
1741 | * Device is larger than can be reflected by READ CAPACITY (10). |
1742 | * Try READ CAPACITY (16). |
1743 | */ |
1744 | |
1745 | memset(&cmd, 0, sizeof(cmd)); |
1746 | cmd.cmd16.opcode = READ_CAPACITY_16; |
1747 | cmd.cmd16.byte2 = SRC16_SERVICE_ACTION; |
1748 | _lto4b(sizeof(datap->data16), cmd.cmd16.len); |
1749 | |
1750 | memset(datap, 0, sizeof(datap->data16)); |
1751 | if (scsipi_command(periph, (void *)&cmd.cmd16, sizeof(cmd.cmd16), |
1752 | (void *)datap, sizeof(datap->data16), SCSIPIRETRIES, 20000, NULL, |
1753 | flags | XS_CTL_DATA_IN | XS_CTL_SILENT) != 0) |
1754 | goto out; |
1755 | |
1756 | *blksize = _4btol(datap->data16.length); |
1757 | rv = _8btol(datap->data16.addr) + 1; |
1758 | |
1759 | out: |
1760 | free(datap, M_TEMP); |
1761 | return rv; |
1762 | } |
1763 | |
1764 | static int |
1765 | sd_get_simplifiedparms(struct sd_softc *sd, struct disk_parms *dp, int flags) |
1766 | { |
1767 | struct { |
1768 | struct scsi_mode_parameter_header_6 ; |
1769 | /* no block descriptor */ |
1770 | u_int8_t pg_code; /* page code (should be 6) */ |
1771 | u_int8_t pg_length; /* page length (should be 11) */ |
1772 | u_int8_t wcd; /* bit0: cache disable */ |
1773 | u_int8_t lbs[2]; /* logical block size */ |
1774 | u_int8_t size[5]; /* number of log. blocks */ |
1775 | u_int8_t pp; /* power/performance */ |
1776 | u_int8_t flags; |
1777 | u_int8_t resvd; |
1778 | } scsipi_sense; |
1779 | u_int64_t blocks; |
1780 | int error, blksize; |
1781 | |
1782 | /* |
1783 | * sd_read_capacity (ie "read capacity") and mode sense page 6 |
1784 | * give the same information. Do both for now, and check |
1785 | * for consistency. |
1786 | * XXX probably differs for removable media |
1787 | */ |
1788 | dp->blksize = SD_DEFAULT_BLKSIZE; |
1789 | if ((blocks = sd_read_capacity(sd->sc_periph, &blksize, flags)) == 0) |
1790 | return (SDGP_RESULT_OFFLINE); /* XXX? */ |
1791 | |
1792 | error = scsipi_mode_sense(sd->sc_periph, SMS_DBD, 6, |
1793 | &scsipi_sense.header, sizeof(scsipi_sense), |
1794 | flags, SDRETRIES, 6000); |
1795 | |
1796 | if (error != 0) |
1797 | return (SDGP_RESULT_OFFLINE); /* XXX? */ |
1798 | |
1799 | dp->blksize = blksize; |
1800 | if (!sd_validate_blksize(NULL, dp->blksize)) |
1801 | dp->blksize = _2btol(scsipi_sense.lbs); |
1802 | if (!sd_validate_blksize(sd->sc_periph, dp->blksize)) |
1803 | dp->blksize = SD_DEFAULT_BLKSIZE; |
1804 | |
1805 | /* |
1806 | * Create a pseudo-geometry. |
1807 | */ |
1808 | dp->heads = 64; |
1809 | dp->sectors = 32; |
1810 | dp->cyls = blocks / (dp->heads * dp->sectors); |
1811 | dp->disksize = _5btol(scsipi_sense.size); |
1812 | if (dp->disksize <= UINT32_MAX && dp->disksize != blocks) { |
1813 | printf("RBC size: mode sense=%llu, get cap=%llu\n" , |
1814 | (unsigned long long)dp->disksize, |
1815 | (unsigned long long)blocks); |
1816 | dp->disksize = blocks; |
1817 | } |
1818 | dp->disksize512 = (dp->disksize * dp->blksize) / DEV_BSIZE; |
1819 | |
1820 | return (SDGP_RESULT_OK); |
1821 | } |
1822 | |
1823 | /* |
1824 | * Get the scsi driver to send a full inquiry to the * device and use the |
1825 | * results to fill out the disk parameter structure. |
1826 | */ |
1827 | static int |
1828 | sd_get_capacity(struct sd_softc *sd, struct disk_parms *dp, int flags) |
1829 | { |
1830 | u_int64_t blocks; |
1831 | int error, blksize; |
1832 | #if 0 |
1833 | int i; |
1834 | u_int8_t *p; |
1835 | #endif |
1836 | |
1837 | dp->disksize = blocks = sd_read_capacity(sd->sc_periph, &blksize, |
1838 | flags); |
1839 | if (blocks == 0) { |
1840 | struct scsipi_read_format_capacities cmd; |
1841 | struct { |
1842 | struct scsipi_capacity_list_header ; |
1843 | struct scsipi_capacity_descriptor desc; |
1844 | } __packed data; |
1845 | |
1846 | memset(&cmd, 0, sizeof(cmd)); |
1847 | memset(&data, 0, sizeof(data)); |
1848 | cmd.opcode = READ_FORMAT_CAPACITIES; |
1849 | _lto2b(sizeof(data), cmd.length); |
1850 | |
1851 | error = scsipi_command(sd->sc_periph, |
1852 | (void *)&cmd, sizeof(cmd), (void *)&data, sizeof(data), |
1853 | SDRETRIES, 20000, NULL, |
1854 | flags | XS_CTL_DATA_IN); |
1855 | if (error == EFTYPE) { |
1856 | /* Medium Format Corrupted, handle as not formatted */ |
1857 | return (SDGP_RESULT_UNFORMATTED); |
1858 | } |
1859 | if (error || data.header.length == 0) |
1860 | return (SDGP_RESULT_OFFLINE); |
1861 | |
1862 | #if 0 |
1863 | printf("rfc: length=%d\n" , data.header.length); |
1864 | printf("rfc result:" ); for (i = sizeof(struct scsipi_capacity_list_header) + data.header.length, p = (void *)&data; i; i--, p++) printf(" %02x" , *p); printf("\n" ); |
1865 | #endif |
1866 | switch (data.desc.byte5 & SCSIPI_CAP_DESC_CODE_MASK) { |
1867 | case SCSIPI_CAP_DESC_CODE_RESERVED: |
1868 | case SCSIPI_CAP_DESC_CODE_FORMATTED: |
1869 | break; |
1870 | |
1871 | case SCSIPI_CAP_DESC_CODE_UNFORMATTED: |
1872 | return (SDGP_RESULT_UNFORMATTED); |
1873 | |
1874 | case SCSIPI_CAP_DESC_CODE_NONE: |
1875 | return (SDGP_RESULT_OFFLINE); |
1876 | } |
1877 | |
1878 | dp->disksize = blocks = _4btol(data.desc.nblks); |
1879 | if (blocks == 0) |
1880 | return (SDGP_RESULT_OFFLINE); /* XXX? */ |
1881 | |
1882 | blksize = _3btol(data.desc.blklen); |
1883 | |
1884 | } else if (!sd_validate_blksize(NULL, blksize)) { |
1885 | struct sd_mode_sense_data scsipi_sense; |
1886 | int big, bsize; |
1887 | struct scsi_general_block_descriptor *bdesc; |
1888 | |
1889 | memset(&scsipi_sense, 0, sizeof(scsipi_sense)); |
1890 | error = sd_mode_sense(sd, 0, &scsipi_sense, |
1891 | sizeof(scsipi_sense.blk_desc), 0, flags | XS_CTL_SILENT, &big); |
1892 | if (!error) { |
1893 | if (big) { |
1894 | bdesc = (void *)(&scsipi_sense.header.big + 1); |
1895 | bsize = _2btol(scsipi_sense.header.big.blk_desc_len); |
1896 | } else { |
1897 | bdesc = (void *)(&scsipi_sense.header.small + 1); |
1898 | bsize = scsipi_sense.header.small.blk_desc_len; |
1899 | } |
1900 | |
1901 | #if 0 |
1902 | printf("page 0 sense:" ); for (i = sizeof(scsipi_sense), p = (void *)&scsipi_sense; i; i--, p++) printf(" %02x" , *p); printf("\n" ); |
1903 | printf("page 0 bsize=%d\n" , bsize); |
1904 | printf("page 0 ok\n" ); |
1905 | #endif |
1906 | |
1907 | if (bsize >= 8) { |
1908 | blksize = _3btol(bdesc->blklen); |
1909 | } |
1910 | } |
1911 | } |
1912 | |
1913 | if (!sd_validate_blksize(sd->sc_periph, blksize)) |
1914 | blksize = SD_DEFAULT_BLKSIZE; |
1915 | |
1916 | dp->blksize = blksize; |
1917 | dp->disksize512 = (blocks * dp->blksize) / DEV_BSIZE; |
1918 | return (0); |
1919 | } |
1920 | |
1921 | static int |
1922 | sd_get_parms_page4(struct sd_softc *sd, struct disk_parms *dp, int flags) |
1923 | { |
1924 | struct sd_mode_sense_data scsipi_sense; |
1925 | int error; |
1926 | int big, byte2; |
1927 | size_t poffset; |
1928 | union scsi_disk_pages *pages; |
1929 | |
1930 | byte2 = SMS_DBD; |
1931 | again: |
1932 | memset(&scsipi_sense, 0, sizeof(scsipi_sense)); |
1933 | error = sd_mode_sense(sd, byte2, &scsipi_sense, |
1934 | (byte2 ? 0 : sizeof(scsipi_sense.blk_desc)) + |
1935 | sizeof(scsipi_sense.pages.rigid_geometry), 4, |
1936 | flags | XS_CTL_SILENT, &big); |
1937 | if (error) { |
1938 | if (byte2 == SMS_DBD) { |
1939 | /* No result; try once more with DBD off */ |
1940 | byte2 = 0; |
1941 | goto again; |
1942 | } |
1943 | return (error); |
1944 | } |
1945 | |
1946 | if (big) { |
1947 | poffset = sizeof scsipi_sense.header.big; |
1948 | poffset += _2btol(scsipi_sense.header.big.blk_desc_len); |
1949 | } else { |
1950 | poffset = sizeof scsipi_sense.header.small; |
1951 | poffset += scsipi_sense.header.small.blk_desc_len; |
1952 | } |
1953 | |
1954 | if (poffset > sizeof(scsipi_sense) - sizeof(pages->rigid_geometry)) |
1955 | return ERESTART; |
1956 | |
1957 | pages = (void *)((u_long)&scsipi_sense + poffset); |
1958 | #if 0 |
1959 | { |
1960 | size_t i; |
1961 | u_int8_t *p; |
1962 | |
1963 | printf("page 4 sense:" ); |
1964 | for (i = sizeof(scsipi_sense), p = (void *)&scsipi_sense; i; |
1965 | i--, p++) |
1966 | printf(" %02x" , *p); |
1967 | printf("\n" ); |
1968 | printf("page 4 pg_code=%d sense=%p/%p\n" , |
1969 | pages->rigid_geometry.pg_code, &scsipi_sense, pages); |
1970 | } |
1971 | #endif |
1972 | |
1973 | if ((pages->rigid_geometry.pg_code & PGCODE_MASK) != 4) |
1974 | return (ERESTART); |
1975 | |
1976 | SC_DEBUG(sd->sc_periph, SCSIPI_DB3, |
1977 | ("%d cyls, %d heads, %d precomp, %d red_write, %d land_zone\n" , |
1978 | _3btol(pages->rigid_geometry.ncyl), |
1979 | pages->rigid_geometry.nheads, |
1980 | _2btol(pages->rigid_geometry.st_cyl_wp), |
1981 | _2btol(pages->rigid_geometry.st_cyl_rwc), |
1982 | _2btol(pages->rigid_geometry.land_zone))); |
1983 | |
1984 | /* |
1985 | * KLUDGE!! (for zone recorded disks) |
1986 | * give a number of sectors so that sec * trks * cyls |
1987 | * is <= disk_size |
1988 | * can lead to wasted space! THINK ABOUT THIS ! |
1989 | */ |
1990 | dp->heads = pages->rigid_geometry.nheads; |
1991 | dp->cyls = _3btol(pages->rigid_geometry.ncyl); |
1992 | if (dp->heads == 0 || dp->cyls == 0) |
1993 | return (ERESTART); |
1994 | dp->sectors = dp->disksize / (dp->heads * dp->cyls); /* XXX */ |
1995 | |
1996 | dp->rot_rate = _2btol(pages->rigid_geometry.rpm); |
1997 | if (dp->rot_rate == 0) |
1998 | dp->rot_rate = 3600; |
1999 | |
2000 | #if 0 |
2001 | printf("page 4 ok\n" ); |
2002 | #endif |
2003 | return (0); |
2004 | } |
2005 | |
2006 | static int |
2007 | sd_get_parms_page5(struct sd_softc *sd, struct disk_parms *dp, int flags) |
2008 | { |
2009 | struct sd_mode_sense_data scsipi_sense; |
2010 | int error; |
2011 | int big, byte2; |
2012 | size_t poffset; |
2013 | union scsi_disk_pages *pages; |
2014 | |
2015 | byte2 = SMS_DBD; |
2016 | again: |
2017 | memset(&scsipi_sense, 0, sizeof(scsipi_sense)); |
2018 | error = sd_mode_sense(sd, 0, &scsipi_sense, |
2019 | (byte2 ? 0 : sizeof(scsipi_sense.blk_desc)) + |
2020 | sizeof(scsipi_sense.pages.flex_geometry), 5, |
2021 | flags | XS_CTL_SILENT, &big); |
2022 | if (error) { |
2023 | if (byte2 == SMS_DBD) { |
2024 | /* No result; try once more with DBD off */ |
2025 | byte2 = 0; |
2026 | goto again; |
2027 | } |
2028 | return (error); |
2029 | } |
2030 | |
2031 | if (big) { |
2032 | poffset = sizeof scsipi_sense.header.big; |
2033 | poffset += _2btol(scsipi_sense.header.big.blk_desc_len); |
2034 | } else { |
2035 | poffset = sizeof scsipi_sense.header.small; |
2036 | poffset += scsipi_sense.header.small.blk_desc_len; |
2037 | } |
2038 | |
2039 | if (poffset > sizeof(scsipi_sense) - sizeof(pages->flex_geometry)) |
2040 | return ERESTART; |
2041 | |
2042 | pages = (void *)((u_long)&scsipi_sense + poffset); |
2043 | #if 0 |
2044 | { |
2045 | size_t i; |
2046 | u_int8_t *p; |
2047 | |
2048 | printf("page 5 sense:" ); |
2049 | for (i = sizeof(scsipi_sense), p = (void *)&scsipi_sense; i; |
2050 | i--, p++) |
2051 | printf(" %02x" , *p); |
2052 | printf("\n" ); |
2053 | printf("page 5 pg_code=%d sense=%p/%p\n" , |
2054 | pages->flex_geometry.pg_code, &scsipi_sense, pages); |
2055 | } |
2056 | #endif |
2057 | |
2058 | if ((pages->flex_geometry.pg_code & PGCODE_MASK) != 5) |
2059 | return (ERESTART); |
2060 | |
2061 | SC_DEBUG(sd->sc_periph, SCSIPI_DB3, |
2062 | ("%d cyls, %d heads, %d sec, %d bytes/sec\n" , |
2063 | _3btol(pages->flex_geometry.ncyl), |
2064 | pages->flex_geometry.nheads, |
2065 | pages->flex_geometry.ph_sec_tr, |
2066 | _2btol(pages->flex_geometry.bytes_s))); |
2067 | |
2068 | dp->heads = pages->flex_geometry.nheads; |
2069 | dp->cyls = _2btol(pages->flex_geometry.ncyl); |
2070 | dp->sectors = pages->flex_geometry.ph_sec_tr; |
2071 | if (dp->heads == 0 || dp->cyls == 0 || dp->sectors == 0) |
2072 | return (ERESTART); |
2073 | |
2074 | dp->rot_rate = _2btol(pages->rigid_geometry.rpm); |
2075 | if (dp->rot_rate == 0) |
2076 | dp->rot_rate = 3600; |
2077 | |
2078 | #if 0 |
2079 | printf("page 5 ok\n" ); |
2080 | #endif |
2081 | return (0); |
2082 | } |
2083 | |
2084 | static int |
2085 | sd_get_parms(struct sd_softc *sd, struct disk_parms *dp, int flags) |
2086 | { |
2087 | int error; |
2088 | |
2089 | /* |
2090 | * If offline, the SDEV_MEDIA_LOADED flag will be |
2091 | * cleared by the caller if necessary. |
2092 | */ |
2093 | if (sd->type == T_SIMPLE_DIRECT) { |
2094 | error = sd_get_simplifiedparms(sd, dp, flags); |
2095 | if (!error) |
2096 | goto setprops; |
2097 | return (error); |
2098 | } |
2099 | |
2100 | error = sd_get_capacity(sd, dp, flags); |
2101 | if (error) |
2102 | return (error); |
2103 | |
2104 | if (sd->type == T_OPTICAL) |
2105 | goto page0; |
2106 | |
2107 | if (sd->sc_periph->periph_flags & PERIPH_REMOVABLE) { |
2108 | if (!sd_get_parms_page5(sd, dp, flags) || |
2109 | !sd_get_parms_page4(sd, dp, flags)) |
2110 | goto setprops; |
2111 | } else { |
2112 | if (!sd_get_parms_page4(sd, dp, flags) || |
2113 | !sd_get_parms_page5(sd, dp, flags)) |
2114 | goto setprops; |
2115 | } |
2116 | |
2117 | page0: |
2118 | printf("%s: fabricating a geometry\n" , device_xname(sd->sc_dev)); |
2119 | /* Try calling driver's method for figuring out geometry. */ |
2120 | if (!sd->sc_periph->periph_channel->chan_adapter->adapt_getgeom || |
2121 | !(*sd->sc_periph->periph_channel->chan_adapter->adapt_getgeom) |
2122 | (sd->sc_periph, dp, dp->disksize)) { |
2123 | /* |
2124 | * Use adaptec standard fictitious geometry |
2125 | * this depends on which controller (e.g. 1542C is |
2126 | * different. but we have to put SOMETHING here..) |
2127 | */ |
2128 | dp->heads = 64; |
2129 | dp->sectors = 32; |
2130 | dp->cyls = dp->disksize / (64 * 32); |
2131 | } |
2132 | dp->rot_rate = 3600; |
2133 | |
2134 | setprops: |
2135 | sd_set_geometry(sd); |
2136 | |
2137 | return (SDGP_RESULT_OK); |
2138 | } |
2139 | |
2140 | static int |
2141 | sd_flush(struct sd_softc *sd, int flags) |
2142 | { |
2143 | struct scsipi_periph *periph = sd->sc_periph; |
2144 | struct scsi_synchronize_cache_10 cmd; |
2145 | |
2146 | /* |
2147 | * If the device is SCSI-2, issue a SYNCHRONIZE CACHE. |
2148 | * We issue with address 0 length 0, which should be |
2149 | * interpreted by the device as "all remaining blocks |
2150 | * starting at address 0". We ignore ILLEGAL REQUEST |
2151 | * in the event that the command is not supported by |
2152 | * the device, and poll for completion so that we know |
2153 | * that the cache has actually been flushed. |
2154 | * |
2155 | * Unless, that is, the device can't handle the SYNCHRONIZE CACHE |
2156 | * command, as indicated by our quirks flags. |
2157 | * |
2158 | * XXX What about older devices? |
2159 | */ |
2160 | if (periph->periph_version < 2 || |
2161 | (periph->periph_quirks & PQUIRK_NOSYNCCACHE)) |
2162 | return (0); |
2163 | |
2164 | sd->flags |= SDF_FLUSHING; |
2165 | memset(&cmd, 0, sizeof(cmd)); |
2166 | cmd.opcode = SCSI_SYNCHRONIZE_CACHE_10; |
2167 | |
2168 | return (scsipi_command(periph, (void *)&cmd, sizeof(cmd), 0, 0, |
2169 | SDRETRIES, 100000, NULL, flags | XS_CTL_IGNORE_ILLEGAL_REQUEST)); |
2170 | } |
2171 | |
2172 | static int |
2173 | sd_getcache(struct sd_softc *sd, int *bitsp) |
2174 | { |
2175 | struct scsipi_periph *periph = sd->sc_periph; |
2176 | struct sd_mode_sense_data scsipi_sense; |
2177 | int error, bits = 0; |
2178 | int big; |
2179 | union scsi_disk_pages *pages; |
2180 | |
2181 | if (periph->periph_version < 2) |
2182 | return (EOPNOTSUPP); |
2183 | |
2184 | memset(&scsipi_sense, 0, sizeof(scsipi_sense)); |
2185 | error = sd_mode_sense(sd, SMS_DBD, &scsipi_sense, |
2186 | sizeof(scsipi_sense.pages.caching_params), 8, 0, &big); |
2187 | if (error) |
2188 | return (error); |
2189 | |
2190 | if (big) |
2191 | pages = (void *)(&scsipi_sense.header.big + 1); |
2192 | else |
2193 | pages = (void *)(&scsipi_sense.header.small + 1); |
2194 | |
2195 | if ((pages->caching_params.flags & CACHING_RCD) == 0) |
2196 | bits |= DKCACHE_READ; |
2197 | if (pages->caching_params.flags & CACHING_WCE) |
2198 | bits |= DKCACHE_WRITE; |
2199 | if (pages->caching_params.pg_code & PGCODE_PS) |
2200 | bits |= DKCACHE_SAVE; |
2201 | |
2202 | memset(&scsipi_sense, 0, sizeof(scsipi_sense)); |
2203 | error = sd_mode_sense(sd, SMS_DBD, &scsipi_sense, |
2204 | sizeof(scsipi_sense.pages.caching_params), |
2205 | SMS_PCTRL_CHANGEABLE|8, 0, &big); |
2206 | if (error == 0) { |
2207 | if (big) |
2208 | pages = (void *)(&scsipi_sense.header.big + 1); |
2209 | else |
2210 | pages = (void *)(&scsipi_sense.header.small + 1); |
2211 | |
2212 | if (pages->caching_params.flags & CACHING_RCD) |
2213 | bits |= DKCACHE_RCHANGE; |
2214 | if (pages->caching_params.flags & CACHING_WCE) |
2215 | bits |= DKCACHE_WCHANGE; |
2216 | } |
2217 | |
2218 | *bitsp = bits; |
2219 | |
2220 | return (0); |
2221 | } |
2222 | |
2223 | static int |
2224 | sd_setcache(struct sd_softc *sd, int bits) |
2225 | { |
2226 | struct scsipi_periph *periph = sd->sc_periph; |
2227 | struct sd_mode_sense_data scsipi_sense; |
2228 | int error; |
2229 | uint8_t oflags, byte2 = 0; |
2230 | int big; |
2231 | union scsi_disk_pages *pages; |
2232 | |
2233 | if (periph->periph_version < 2) |
2234 | return (EOPNOTSUPP); |
2235 | |
2236 | memset(&scsipi_sense, 0, sizeof(scsipi_sense)); |
2237 | error = sd_mode_sense(sd, SMS_DBD, &scsipi_sense, |
2238 | sizeof(scsipi_sense.pages.caching_params), 8, 0, &big); |
2239 | if (error) |
2240 | return (error); |
2241 | |
2242 | if (big) |
2243 | pages = (void *)(&scsipi_sense.header.big + 1); |
2244 | else |
2245 | pages = (void *)(&scsipi_sense.header.small + 1); |
2246 | |
2247 | oflags = pages->caching_params.flags; |
2248 | |
2249 | if (bits & DKCACHE_READ) |
2250 | pages->caching_params.flags &= ~CACHING_RCD; |
2251 | else |
2252 | pages->caching_params.flags |= CACHING_RCD; |
2253 | |
2254 | if (bits & DKCACHE_WRITE) |
2255 | pages->caching_params.flags |= CACHING_WCE; |
2256 | else |
2257 | pages->caching_params.flags &= ~CACHING_WCE; |
2258 | |
2259 | if (oflags == pages->caching_params.flags) |
2260 | return (0); |
2261 | |
2262 | pages->caching_params.pg_code &= PGCODE_MASK; |
2263 | |
2264 | if (bits & DKCACHE_SAVE) |
2265 | byte2 |= SMS_SP; |
2266 | |
2267 | return (sd_mode_select(sd, byte2|SMS_PF, &scsipi_sense, |
2268 | sizeof(struct scsi_mode_page_header) + |
2269 | pages->caching_params.pg_length, 0, big)); |
2270 | } |
2271 | |
2272 | static void |
2273 | sd_set_geometry(struct sd_softc *sd) |
2274 | { |
2275 | struct disk_geom *dg = &sd->sc_dk.dk_geom; |
2276 | |
2277 | memset(dg, 0, sizeof(*dg)); |
2278 | |
2279 | dg->dg_secperunit = sd->params.disksize; |
2280 | dg->dg_secsize = sd->params.blksize; |
2281 | dg->dg_nsectors = sd->params.sectors; |
2282 | dg->dg_ntracks = sd->params.heads; |
2283 | dg->dg_ncylinders = sd->params.cyls; |
2284 | |
2285 | disk_set_info(sd->sc_dev, &sd->sc_dk, NULL); |
2286 | } |
2287 | |