]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/cam/scsi/scsi_da.c
This commit was generated by cvs2svn to compensate for changes in r159952,
[FreeBSD/FreeBSD.git] / sys / cam / scsi / scsi_da.c
1 /*-
2  * Implementation of SCSI Direct Access Peripheral driver for CAM.
3  *
4  * Copyright (c) 1997 Justin T. Gibbs.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions, and the following disclaimer,
12  *    without modification, immediately at the beginning of the file.
13  * 2. The name of the author may not be used to endorse or promote products
14  *    derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
20  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/param.h>
33
34 #ifdef _KERNEL
35 #include <sys/systm.h>
36 #include <sys/kernel.h>
37 #include <sys/bio.h>
38 #include <sys/sysctl.h>
39 #include <sys/taskqueue.h>
40 #endif /* _KERNEL */
41
42 #include <sys/devicestat.h>
43 #include <sys/conf.h>
44 #include <sys/eventhandler.h>
45 #include <sys/malloc.h>
46 #include <sys/cons.h>
47
48 #include <machine/md_var.h>
49
50 #include <vm/vm.h>
51 #include <vm/pmap.h>
52
53 #include <geom/geom_disk.h>
54
55 #ifndef _KERNEL
56 #include <stdio.h>
57 #include <string.h>
58 #endif /* _KERNEL */
59
60 #include <cam/cam.h>
61 #include <cam/cam_ccb.h>
62 #include <cam/cam_periph.h>
63 #include <cam/cam_xpt_periph.h>
64
65 #include <cam/scsi/scsi_message.h>
66
67 #ifndef _KERNEL 
68 #include <cam/scsi/scsi_da.h>
69 #endif /* !_KERNEL */
70
71 #ifdef _KERNEL
72 typedef enum {
73         DA_STATE_PROBE,
74         DA_STATE_PROBE2,
75         DA_STATE_NORMAL
76 } da_state;
77
78 typedef enum {
79         DA_FLAG_PACK_INVALID    = 0x001,
80         DA_FLAG_NEW_PACK        = 0x002,
81         DA_FLAG_PACK_LOCKED     = 0x004,
82         DA_FLAG_PACK_REMOVABLE  = 0x008,
83         DA_FLAG_TAGGED_QUEUING  = 0x010,
84         DA_FLAG_NEED_OTAG       = 0x020,
85         DA_FLAG_WENT_IDLE       = 0x040,
86         DA_FLAG_RETRY_UA        = 0x080,
87         DA_FLAG_OPEN            = 0x100,
88         DA_FLAG_SCTX_INIT       = 0x200
89 } da_flags;
90
91 typedef enum {
92         DA_Q_NONE               = 0x00,
93         DA_Q_NO_SYNC_CACHE      = 0x01,
94         DA_Q_NO_6_BYTE          = 0x02,
95         DA_Q_NO_PREVENT         = 0x04
96 } da_quirks;
97
98 typedef enum {
99         DA_CCB_PROBE            = 0x01,
100         DA_CCB_PROBE2           = 0x02,
101         DA_CCB_BUFFER_IO        = 0x03,
102         DA_CCB_WAITING          = 0x04,
103         DA_CCB_DUMP             = 0x05,
104         DA_CCB_TYPE_MASK        = 0x0F,
105         DA_CCB_RETRY_UA         = 0x10
106 } da_ccb_state;
107
108 /* Offsets into our private area for storing information */
109 #define ccb_state       ppriv_field0
110 #define ccb_bp          ppriv_ptr1
111
112 struct disk_params {
113         u_int8_t  heads;
114         u_int32_t cylinders;
115         u_int8_t  secs_per_track;
116         u_int32_t secsize;      /* Number of bytes/sector */
117         u_int64_t sectors;      /* total number sectors */
118 };
119
120 struct da_softc {
121         struct   bio_queue_head bio_queue;
122         SLIST_ENTRY(da_softc) links;
123         LIST_HEAD(, ccb_hdr) pending_ccbs;
124         da_state state;
125         da_flags flags; 
126         da_quirks quirks;
127         int      minimum_cmd_size;
128         int      ordered_tag_count;
129         int      outstanding_cmds;
130         struct   disk_params params;
131         struct   disk *disk;
132         union    ccb saved_ccb;
133         struct task             sysctl_task;
134         struct sysctl_ctx_list  sysctl_ctx;
135         struct sysctl_oid       *sysctl_tree;
136 };
137
138 struct da_quirk_entry {
139         struct scsi_inquiry_pattern inq_pat;
140         da_quirks quirks;
141 };
142
143 static const char quantum[] = "QUANTUM";
144 static const char microp[] = "MICROP";
145
146 static struct da_quirk_entry da_quirk_table[] =
147 {
148         /* SPI, FC devices */
149         {
150                 /*
151                  * Fujitsu M2513A MO drives.
152                  * Tested devices: M2513A2 firmware versions 1200 & 1300.
153                  * (dip switch selects whether T_DIRECT or T_OPTICAL device)
154                  * Reported by: W.Scholten <whs@xs4all.nl>
155                  */
156                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "FUJITSU", "M2513A", "*"},
157                 /*quirks*/ DA_Q_NO_SYNC_CACHE
158         },
159         {
160                 /* See above. */
161                 {T_OPTICAL, SIP_MEDIA_REMOVABLE, "FUJITSU", "M2513A", "*"},
162                 /*quirks*/ DA_Q_NO_SYNC_CACHE
163         },
164         {
165                 /*
166                  * This particular Fujitsu drive doesn't like the
167                  * synchronize cache command.
168                  * Reported by: Tom Jackson <toj@gorilla.net>
169                  */
170                 {T_DIRECT, SIP_MEDIA_FIXED, "FUJITSU", "M2954*", "*"},
171                 /*quirks*/ DA_Q_NO_SYNC_CACHE
172         
173         },
174         {
175                 /*
176                  * This drive doesn't like the synchronize cache command
177                  * either.  Reported by: Matthew Jacob <mjacob@feral.com>
178                  * in NetBSD PR kern/6027, August 24, 1998.
179                  */
180                 {T_DIRECT, SIP_MEDIA_FIXED, microp, "2217*", "*"},
181                 /*quirks*/ DA_Q_NO_SYNC_CACHE
182         },
183         {
184                 /*
185                  * This drive doesn't like the synchronize cache command
186                  * either.  Reported by: Hellmuth Michaelis (hm@kts.org)
187                  * (PR 8882).
188                  */
189                 {T_DIRECT, SIP_MEDIA_FIXED, microp, "2112*", "*"},
190                 /*quirks*/ DA_Q_NO_SYNC_CACHE
191         },
192         {
193                 /*
194                  * Doesn't like the synchronize cache command.
195                  * Reported by: Blaz Zupan <blaz@gold.amis.net>
196                  */
197                 {T_DIRECT, SIP_MEDIA_FIXED, "NEC", "D3847*", "*"},
198                 /*quirks*/ DA_Q_NO_SYNC_CACHE
199         },
200         {
201                 /*
202                  * Doesn't like the synchronize cache command.
203                  * Reported by: Blaz Zupan <blaz@gold.amis.net>
204                  */
205                 {T_DIRECT, SIP_MEDIA_FIXED, quantum, "MAVERICK 540S", "*"},
206                 /*quirks*/ DA_Q_NO_SYNC_CACHE
207         },
208         {
209                 /*
210                  * Doesn't like the synchronize cache command.
211                  */
212                 {T_DIRECT, SIP_MEDIA_FIXED, quantum, "LPS525S", "*"},
213                 /*quirks*/ DA_Q_NO_SYNC_CACHE
214         },
215         {
216                 /*
217                  * Doesn't like the synchronize cache command.
218                  * Reported by: walter@pelissero.de
219                  */
220                 {T_DIRECT, SIP_MEDIA_FIXED, quantum, "LPS540S", "*"},
221                 /*quirks*/ DA_Q_NO_SYNC_CACHE
222         },
223         {
224                 /*
225                  * Doesn't work correctly with 6 byte reads/writes.
226                  * Returns illegal request, and points to byte 9 of the
227                  * 6-byte CDB.
228                  * Reported by:  Adam McDougall <bsdx@spawnet.com>
229                  */
230                 {T_DIRECT, SIP_MEDIA_FIXED, quantum, "VIKING 4*", "*"},
231                 /*quirks*/ DA_Q_NO_6_BYTE
232         },
233         {
234                 /* See above. */
235                 {T_DIRECT, SIP_MEDIA_FIXED, quantum, "VIKING 2*", "*"},
236                 /*quirks*/ DA_Q_NO_6_BYTE
237         },
238         {
239                 /*
240                  * Doesn't like the synchronize cache command.
241                  * Reported by: walter@pelissero.de
242                  */
243                 {T_DIRECT, SIP_MEDIA_FIXED, "CONNER", "CP3500*", "*"},
244                 /*quirks*/ DA_Q_NO_SYNC_CACHE
245         },
246         {
247                 /*
248                  * The CISS RAID controllers do not support SYNC_CACHE
249                  */
250                 {T_DIRECT, SIP_MEDIA_FIXED, "COMPAQ", "RAID*", "*"},
251                 /*quirks*/ DA_Q_NO_SYNC_CACHE
252         },
253         /* USB mass storage devices supported by umass(4) */
254         {
255                 /*
256                  * EXATELECOM (Sigmatel) i-Bead 100/105 USB Flash MP3 Player
257                  * PR: kern/51675
258                  */
259                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "EXATEL", "i-BEAD10*", "*"},
260                 /*quirks*/ DA_Q_NO_SYNC_CACHE
261         },
262         {
263                 /*
264                  * Power Quotient Int. (PQI) USB flash key
265                  * PR: kern/53067
266                  */
267                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "Generic*", "USB Flash Disk*",
268                 "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
269         }, 
270         {
271                 /*
272                  * Creative Nomad MUVO mp3 player (USB)
273                  * PR: kern/53094
274                  */
275                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "CREATIVE", "NOMAD_MUVO", "*"},
276                 /*quirks*/ DA_Q_NO_SYNC_CACHE|DA_Q_NO_PREVENT
277         },
278         {
279                 /*
280                  * Jungsoft NEXDISK USB flash key
281                  * PR: kern/54737
282                  */
283                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "JUNGSOFT", "NEXDISK*", "*"},
284                 /*quirks*/ DA_Q_NO_SYNC_CACHE
285         },
286         {
287                 /*
288                  * FreeDik USB Mini Data Drive
289                  * PR: kern/54786
290                  */
291                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "FreeDik*", "Mini Data Drive",
292                 "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
293         },
294         {
295                 /*
296                  * Sigmatel USB Flash MP3 Player
297                  * PR: kern/57046
298                  */
299                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "SigmaTel", "MSCN", "*"},
300                 /*quirks*/ DA_Q_NO_SYNC_CACHE|DA_Q_NO_PREVENT
301         },
302         {
303                 /*
304                  * Neuros USB Digital Audio Computer
305                  * PR: kern/63645
306                  */
307                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "NEUROS", "dig. audio comp.",
308                 "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
309         },
310         {
311                 /*
312                  * SEAGRAND NP-900 MP3 Player
313                  * PR: kern/64563
314                  */
315                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "SEAGRAND", "NP-900*", "*"},
316                 /*quirks*/ DA_Q_NO_SYNC_CACHE|DA_Q_NO_PREVENT
317         },
318         {
319                 /*
320                  * iRiver iFP MP3 player (with UMS Firmware)
321                  * PR: kern/54881, i386/63941, kern/66124
322                  */
323                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "iRiver", "iFP*", "*"},
324                 /*quirks*/ DA_Q_NO_SYNC_CACHE
325         },
326         {
327                 /*
328                  * Frontier Labs NEX IA+ Digital Audio Player, rev 1.10/0.01
329                  * PR: kern/70158
330                  */
331                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "FL" , "Nex*", "*"},
332                 /*quirks*/ DA_Q_NO_SYNC_CACHE
333         },
334         {
335                 /*
336                  * ZICPlay USB MP3 Player with FM
337                  * PR: kern/75057
338                  */
339                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "ACTIONS*" , "USB DISK*", "*"},
340                 /*quirks*/ DA_Q_NO_SYNC_CACHE
341         },
342         {
343                 /*
344                  * TEAC USB floppy mechanisms
345                  */
346                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "TEAC" , "FD-05*", "*"},
347                 /*quirks*/ DA_Q_NO_SYNC_CACHE
348         },
349         {
350                 /*
351                  * Kingston DataTraveler II+ USB Pen-Drive.
352                  * Reported by: Pawel Jakub Dawidek <pjd@FreeBSD.org>
353                  */
354                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "Kingston" , "DataTraveler II+",
355                 "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
356         },
357         {
358                 /*
359                  * Motorola E398 Mobile Phone (TransFlash memory card).
360                  * Reported by: Wojciech A. Koszek <dunstan@FreeBSD.czest.pl>
361                  * PR: usb/89889
362                  */
363                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "Motorola" , "Motorola Phone",
364                 "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
365         },
366         {
367                 /*
368                  * Qware BeatZkey! Pro
369                  * PR: usb/79164
370                  */
371                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "GENERIC", "USB DISK DEVICE",
372                 "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
373         },
374         {
375                 /*
376                  * Time DPA20B 1GB MP3 Player
377                  * PR: usb/81846
378                  */
379                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "USB2.0*", "(FS) FLASH DISK*",
380                 "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
381         },
382         {
383                 /*
384                  * Samsung USB key 128Mb
385                  * PR: usb/90081
386                  */
387                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "USB-DISK", "FreeDik-FlashUsb",
388                 "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
389         },
390         {
391                 /*
392                  * Kingston DataTraveler 2.0 USB Flash memory.
393                  * PR: usb/89196
394                  */
395                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "Kingston", "DataTraveler 2.0",
396                 "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
397         },
398         {
399                 /*
400                  * Creative MUVO Slim mp3 player (USB)
401                  * PR: usb/86131
402                  */
403                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "CREATIVE", "MuVo Slim",
404                 "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE|DA_Q_NO_PREVENT
405                 },
406         {
407                 /*
408                  * United MP5512 Portable MP3 Player (2-in-1 USB DISK/MP3)
409                  * PR: usb/80487
410                  */
411                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "Generic*", "MUSIC DISK",
412                 "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
413         },
414         {
415                 /*
416                  * SanDisk Micro Cruzer 128MB
417                  * PR: usb/75970
418                  */
419                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "SanDisk" , "Micro Cruzer",
420                 "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
421         },
422         {
423                 /*
424                  * TOSHIBA TransMemory USB sticks
425                  * PR: kern/94660
426                  */
427                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "TOSHIBA", "TransMemory",
428                 "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
429         },
430         {
431                 /*
432                  * PNY USB Flash keys
433                  * PR: usb/75578, usb/72344, usb/65436 
434                  */
435                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "*" , "USB DISK*",
436                 "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
437         },
438         {
439                 /*
440                  * Genesys 6-in-1 Card Reader
441                  * PR: usb/94647
442                  */
443                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "Generic*", "STORAGE DEVICE*",
444                 "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
445         },
446 };
447
448 static  disk_strategy_t dastrategy;
449 static  dumper_t        dadump;
450 static  periph_init_t   dainit;
451 static  void            daasync(void *callback_arg, u_int32_t code,
452                                 struct cam_path *path, void *arg);
453 static  void            dasysctlinit(void *context, int pending);
454 static  int             dacmdsizesysctl(SYSCTL_HANDLER_ARGS);
455 static  periph_ctor_t   daregister;
456 static  periph_dtor_t   dacleanup;
457 static  periph_start_t  dastart;
458 static  periph_oninv_t  daoninvalidate;
459 static  void            dadone(struct cam_periph *periph,
460                                union ccb *done_ccb);
461 static  int             daerror(union ccb *ccb, u_int32_t cam_flags,
462                                 u_int32_t sense_flags);
463 static void             daprevent(struct cam_periph *periph, int action);
464 static int              dagetcapacity(struct cam_periph *periph);
465 static void             dasetgeom(struct cam_periph *periph, uint32_t block_len,
466                                   uint64_t maxsector);
467 static timeout_t        dasendorderedtag;
468 static void             dashutdown(void *arg, int howto);
469
470 #ifndef DA_DEFAULT_TIMEOUT
471 #define DA_DEFAULT_TIMEOUT 60   /* Timeout in seconds */
472 #endif
473
474 #ifndef DA_DEFAULT_RETRY
475 #define DA_DEFAULT_RETRY        4
476 #endif
477
478 static int da_retry_count = DA_DEFAULT_RETRY;
479 static int da_default_timeout = DA_DEFAULT_TIMEOUT;
480
481 SYSCTL_NODE(_kern_cam, OID_AUTO, da, CTLFLAG_RD, 0,
482             "CAM Direct Access Disk driver");
483 SYSCTL_INT(_kern_cam_da, OID_AUTO, retry_count, CTLFLAG_RW,
484            &da_retry_count, 0, "Normal I/O retry count");
485 TUNABLE_INT("kern.cam.da.retry_count", &da_retry_count);
486 SYSCTL_INT(_kern_cam_da, OID_AUTO, default_timeout, CTLFLAG_RW,
487            &da_default_timeout, 0, "Normal I/O timeout (in seconds)");
488 TUNABLE_INT("kern.cam.da.default_timeout", &da_default_timeout);
489
490 /*
491  * DA_ORDEREDTAG_INTERVAL determines how often, relative
492  * to the default timeout, we check to see whether an ordered
493  * tagged transaction is appropriate to prevent simple tag
494  * starvation.  Since we'd like to ensure that there is at least
495  * 1/2 of the timeout length left for a starved transaction to
496  * complete after we've sent an ordered tag, we must poll at least
497  * four times in every timeout period.  This takes care of the worst
498  * case where a starved transaction starts during an interval that
499  * meets the requirement "don't send an ordered tag" test so it takes
500  * us two intervals to determine that a tag must be sent.
501  */
502 #ifndef DA_ORDEREDTAG_INTERVAL
503 #define DA_ORDEREDTAG_INTERVAL 4
504 #endif
505
506 static struct periph_driver dadriver =
507 {
508         dainit, "da",
509         TAILQ_HEAD_INITIALIZER(dadriver.units), /* generation */ 0
510 };
511
512 PERIPHDRIVER_DECLARE(da, dadriver);
513
514 static SLIST_HEAD(,da_softc) softc_list;
515
516 static int
517 daopen(struct disk *dp)
518 {
519         struct cam_periph *periph;
520         struct da_softc *softc;
521         int unit;
522         int error;
523         int s;
524
525         s = splsoftcam();
526         periph = (struct cam_periph *)dp->d_drv1;
527         if (periph == NULL) {
528                 splx(s);
529                 return (ENXIO); 
530         }
531         unit = periph->unit_number;
532
533         softc = (struct da_softc *)periph->softc;
534
535         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,
536             ("daopen: disk=%s%d (unit %d)\n", dp->d_name, dp->d_unit,
537              unit));
538
539         if ((error = cam_periph_lock(periph, PRIBIO|PCATCH)) != 0)
540                 return (error); /* error code from tsleep */
541
542         if (cam_periph_acquire(periph) != CAM_REQ_CMP)
543                 return(ENXIO);
544         softc->flags |= DA_FLAG_OPEN;
545
546         if ((softc->flags & DA_FLAG_PACK_INVALID) != 0) {
547                 /* Invalidate our pack information. */
548                 softc->flags &= ~DA_FLAG_PACK_INVALID;
549         }
550         splx(s);
551
552         error = dagetcapacity(periph);
553
554         if (error == 0) {
555
556                 softc->disk->d_sectorsize = softc->params.secsize;
557                 softc->disk->d_mediasize = softc->params.secsize * (off_t)softc->params.sectors;
558                 /* XXX: these are not actually "firmware" values, so they may be wrong */
559                 softc->disk->d_fwsectors = softc->params.secs_per_track;
560                 softc->disk->d_fwheads = softc->params.heads;
561                 softc->disk->d_devstat->block_size = softc->params.secsize;
562                 softc->disk->d_devstat->flags &= ~DEVSTAT_BS_UNAVAILABLE;
563         }
564         
565         if (error == 0) {
566                 if ((softc->flags & DA_FLAG_PACK_REMOVABLE) != 0 &&
567                     (softc->quirks & DA_Q_NO_PREVENT) == 0)
568                         daprevent(periph, PR_PREVENT);
569         } else {
570                 softc->flags &= ~DA_FLAG_OPEN;
571                 cam_periph_release(periph);
572         }
573         cam_periph_unlock(periph);
574         return (error);
575 }
576
577 static int
578 daclose(struct disk *dp)
579 {
580         struct  cam_periph *periph;
581         struct  da_softc *softc;
582         int     error;
583
584         periph = (struct cam_periph *)dp->d_drv1;
585         if (periph == NULL)
586                 return (ENXIO); 
587
588         softc = (struct da_softc *)periph->softc;
589
590         if ((error = cam_periph_lock(periph, PRIBIO)) != 0) {
591                 return (error); /* error code from tsleep */
592         }
593
594         if ((softc->quirks & DA_Q_NO_SYNC_CACHE) == 0) {
595                 union   ccb *ccb;
596
597                 ccb = cam_periph_getccb(periph, /*priority*/1);
598
599                 scsi_synchronize_cache(&ccb->csio,
600                                        /*retries*/1,
601                                        /*cbfcnp*/dadone,
602                                        MSG_SIMPLE_Q_TAG,
603                                        /*begin_lba*/0,/* Cover the whole disk */
604                                        /*lb_count*/0,
605                                        SSD_FULL_SIZE,
606                                        5 * 60 * 1000);
607
608                 cam_periph_runccb(ccb, /*error_routine*/NULL, /*cam_flags*/0,
609                                   /*sense_flags*/SF_RETRY_UA,
610                                   softc->disk->d_devstat);
611
612                 if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
613                         if ((ccb->ccb_h.status & CAM_STATUS_MASK) ==
614                              CAM_SCSI_STATUS_ERROR) {
615                                 int asc, ascq;
616                                 int sense_key, error_code;
617
618                                 scsi_extract_sense(&ccb->csio.sense_data,
619                                                    &error_code,
620                                                    &sense_key, 
621                                                    &asc, &ascq);
622                                 if (sense_key != SSD_KEY_ILLEGAL_REQUEST)
623                                         scsi_sense_print(&ccb->csio);
624                         } else {
625                                 xpt_print_path(periph->path);
626                                 printf("Synchronize cache failed, status "
627                                        "== 0x%x, scsi status == 0x%x\n",
628                                        ccb->csio.ccb_h.status,
629                                        ccb->csio.scsi_status);
630                         }
631                 }
632
633                 if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
634                         cam_release_devq(ccb->ccb_h.path,
635                                          /*relsim_flags*/0,
636                                          /*reduction*/0,
637                                          /*timeout*/0,
638                                          /*getcount_only*/0);
639
640                 xpt_release_ccb(ccb);
641
642         }
643
644         if ((softc->flags & DA_FLAG_PACK_REMOVABLE) != 0) {
645                 if ((softc->quirks & DA_Q_NO_PREVENT) == 0)
646                         daprevent(periph, PR_ALLOW);
647                 /*
648                  * If we've got removeable media, mark the blocksize as
649                  * unavailable, since it could change when new media is
650                  * inserted.
651                  */
652                 softc->disk->d_devstat->flags |= DEVSTAT_BS_UNAVAILABLE;
653         }
654
655         softc->flags &= ~DA_FLAG_OPEN;
656         cam_periph_unlock(periph);
657         cam_periph_release(periph);
658         return (0);     
659 }
660
661 /*
662  * Actually translate the requested transfer into one the physical driver
663  * can understand.  The transfer is described by a buf and will include
664  * only one physical transfer.
665  */
666 static void
667 dastrategy(struct bio *bp)
668 {
669         struct cam_periph *periph;
670         struct da_softc *softc;
671         int    s;
672         
673         periph = (struct cam_periph *)bp->bio_disk->d_drv1;
674         if (periph == NULL) {
675                 biofinish(bp, NULL, ENXIO);
676                 return;
677         }
678         softc = (struct da_softc *)periph->softc;
679 #if 0
680         /*
681          * check it's not too big a transfer for our adapter
682          */
683         scsi_minphys(bp,&sd_switch);
684 #endif
685
686         /*
687          * Mask interrupts so that the pack cannot be invalidated until
688          * after we are in the queue.  Otherwise, we might not properly
689          * clean up one of the buffers.
690          */
691         s = splbio();
692         
693         /*
694          * If the device has been made invalid, error out
695          */
696         if ((softc->flags & DA_FLAG_PACK_INVALID)) {
697                 splx(s);
698                 biofinish(bp, NULL, ENXIO);
699                 return;
700         }
701         
702         /*
703          * Place it in the queue of disk activities for this disk
704          */
705         bioq_disksort(&softc->bio_queue, bp);
706
707         splx(s);
708         
709         /*
710          * Schedule ourselves for performing the work.
711          */
712         xpt_schedule(periph, /* XXX priority */1);
713
714         return;
715 }
716
717 static int
718 dadump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size_t length)
719 {
720         struct      cam_periph *periph;
721         struct      da_softc *softc;
722         u_int       secsize;
723         struct      ccb_scsiio csio;
724         struct      disk *dp;
725
726         dp = arg;
727         periph = dp->d_drv1;
728         if (periph == NULL)
729                 return (ENXIO);
730         softc = (struct da_softc *)periph->softc;
731         secsize = softc->params.secsize;
732         
733         if ((softc->flags & DA_FLAG_PACK_INVALID) != 0)
734                 return (ENXIO);
735
736         if (length > 0) {
737                 xpt_setup_ccb(&csio.ccb_h, periph->path, /*priority*/1);
738                 csio.ccb_h.ccb_state = DA_CCB_DUMP;
739                 scsi_read_write(&csio,
740                                 /*retries*/1,
741                                 dadone,
742                                 MSG_ORDERED_Q_TAG,
743                                 /*read*/FALSE,
744                                 /*byte2*/0,
745                                 /*minimum_cmd_size*/ softc->minimum_cmd_size,
746                                 offset / secsize,
747                                 length / secsize,
748                                 /*data_ptr*/(u_int8_t *) virtual,
749                                 /*dxfer_len*/length,
750                                 /*sense_len*/SSD_FULL_SIZE,
751                                 DA_DEFAULT_TIMEOUT * 1000);             
752                 xpt_polled_action((union ccb *)&csio);
753
754                 if ((csio.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
755                         printf("Aborting dump due to I/O error.\n");
756                         if ((csio.ccb_h.status & CAM_STATUS_MASK) ==
757                              CAM_SCSI_STATUS_ERROR)
758                                 scsi_sense_print(&csio);
759                         else
760                                 printf("status == 0x%x, scsi status == 0x%x\n",
761                                        csio.ccb_h.status, csio.scsi_status);
762                         return(EIO);
763                 }
764                 return(0);
765         } 
766                 
767         /*
768          * Sync the disk cache contents to the physical media.
769          */
770         if ((softc->quirks & DA_Q_NO_SYNC_CACHE) == 0) {
771
772                 xpt_setup_ccb(&csio.ccb_h, periph->path, /*priority*/1);
773                 csio.ccb_h.ccb_state = DA_CCB_DUMP;
774                 scsi_synchronize_cache(&csio,
775                                        /*retries*/1,
776                                        /*cbfcnp*/dadone,
777                                        MSG_SIMPLE_Q_TAG,
778                                        /*begin_lba*/0,/* Cover the whole disk */
779                                        /*lb_count*/0,
780                                        SSD_FULL_SIZE,
781                                        5 * 60 * 1000);
782                 xpt_polled_action((union ccb *)&csio);
783
784                 if ((csio.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
785                         if ((csio.ccb_h.status & CAM_STATUS_MASK) ==
786                              CAM_SCSI_STATUS_ERROR) {
787                                 int asc, ascq;
788                                 int sense_key, error_code;
789
790                                 scsi_extract_sense(&csio.sense_data,
791                                                    &error_code,
792                                                    &sense_key, 
793                                                    &asc, &ascq);
794                                 if (sense_key != SSD_KEY_ILLEGAL_REQUEST)
795                                         scsi_sense_print(&csio);
796                         } else {
797                                 xpt_print_path(periph->path);
798                                 printf("Synchronize cache failed, status "
799                                        "== 0x%x, scsi status == 0x%x\n",
800                                        csio.ccb_h.status, csio.scsi_status);
801                         }
802                 }
803         }
804         return (0);
805 }
806
807 static void
808 dainit(void)
809 {
810         cam_status status;
811         struct cam_path *path;
812
813         SLIST_INIT(&softc_list);
814         
815         /*
816          * Install a global async callback.  This callback will
817          * receive async callbacks like "new device found".
818          */
819         status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID,
820                                  CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
821
822         if (status == CAM_REQ_CMP) {
823                 struct ccb_setasync csa;
824
825                 xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5);
826                 csa.ccb_h.func_code = XPT_SASYNC_CB;
827                 csa.event_enable = AC_FOUND_DEVICE;
828                 csa.callback = daasync;
829                 csa.callback_arg = NULL;
830                 xpt_action((union ccb *)&csa);
831                 status = csa.ccb_h.status;
832                 xpt_free_path(path);
833         }
834
835         if (status != CAM_REQ_CMP) {
836                 printf("da: Failed to attach master async callback "
837                        "due to status 0x%x!\n", status);
838         } else {
839
840                 /*
841                  * Schedule a periodic event to occasionally send an
842                  * ordered tag to a device.
843                  */
844                 timeout(dasendorderedtag, NULL,
845                         (DA_DEFAULT_TIMEOUT * hz) / DA_ORDEREDTAG_INTERVAL);
846
847                 /* Register our shutdown event handler */
848                 if ((EVENTHANDLER_REGISTER(shutdown_post_sync, dashutdown, 
849                                            NULL, SHUTDOWN_PRI_DEFAULT)) == NULL)
850                     printf("dainit: shutdown event registration failed!\n");
851         }
852 }
853
854 static void
855 daoninvalidate(struct cam_periph *periph)
856 {
857         int s;
858         struct da_softc *softc;
859         struct ccb_setasync csa;
860
861         softc = (struct da_softc *)periph->softc;
862
863         /*
864          * De-register any async callbacks.
865          */
866         xpt_setup_ccb(&csa.ccb_h, periph->path,
867                       /* priority */ 5);
868         csa.ccb_h.func_code = XPT_SASYNC_CB;
869         csa.event_enable = 0;
870         csa.callback = daasync;
871         csa.callback_arg = periph;
872         xpt_action((union ccb *)&csa);
873
874         softc->flags |= DA_FLAG_PACK_INVALID;
875
876         /*
877          * Although the oninvalidate() routines are always called at
878          * splsoftcam, we need to be at splbio() here to keep the buffer
879          * queue from being modified while we traverse it.
880          */
881         s = splbio();
882
883         /*
884          * Return all queued I/O with ENXIO.
885          * XXX Handle any transactions queued to the card
886          *     with XPT_ABORT_CCB.
887          */
888         bioq_flush(&softc->bio_queue, NULL, ENXIO);
889         splx(s);
890
891         SLIST_REMOVE(&softc_list, softc, da_softc, links);
892
893         disk_gone(softc->disk);
894         xpt_print_path(periph->path);
895         printf("lost device\n");
896 }
897
898 static void
899 dacleanup(struct cam_periph *periph)
900 {
901         struct da_softc *softc;
902
903         softc = (struct da_softc *)periph->softc;
904
905         xpt_print_path(periph->path);
906         printf("removing device entry\n");
907         /*
908          * If we can't free the sysctl tree, oh well...
909          */
910         if ((softc->flags & DA_FLAG_SCTX_INIT) != 0
911             && sysctl_ctx_free(&softc->sysctl_ctx) != 0) {
912                 xpt_print_path(periph->path);
913                 printf("can't remove sysctl context\n");
914         }
915         disk_destroy(softc->disk);
916         free(softc, M_DEVBUF);
917 }
918
919 static void
920 daasync(void *callback_arg, u_int32_t code,
921         struct cam_path *path, void *arg)
922 {
923         struct cam_periph *periph;
924
925         periph = (struct cam_periph *)callback_arg;
926         switch (code) {
927         case AC_FOUND_DEVICE:
928         {
929                 struct ccb_getdev *cgd;
930                 cam_status status;
931  
932                 cgd = (struct ccb_getdev *)arg;
933                 if (cgd == NULL)
934                         break;
935
936                 if (SID_TYPE(&cgd->inq_data) != T_DIRECT
937                     && SID_TYPE(&cgd->inq_data) != T_RBC
938                     && SID_TYPE(&cgd->inq_data) != T_OPTICAL)
939                         break;
940
941                 /*
942                  * Allocate a peripheral instance for
943                  * this device and start the probe
944                  * process.
945                  */
946                 status = cam_periph_alloc(daregister, daoninvalidate,
947                                           dacleanup, dastart,
948                                           "da", CAM_PERIPH_BIO,
949                                           cgd->ccb_h.path, daasync,
950                                           AC_FOUND_DEVICE, cgd);
951
952                 if (status != CAM_REQ_CMP
953                  && status != CAM_REQ_INPROG)
954                         printf("daasync: Unable to attach to new device "
955                                 "due to status 0x%x\n", status);
956                 break;
957         }
958         case AC_SENT_BDR:
959         case AC_BUS_RESET:
960         {
961                 struct da_softc *softc;
962                 struct ccb_hdr *ccbh;
963                 int s;
964
965                 softc = (struct da_softc *)periph->softc;
966                 s = splsoftcam();
967                 /*
968                  * Don't fail on the expected unit attention
969                  * that will occur.
970                  */
971                 softc->flags |= DA_FLAG_RETRY_UA;
972                 LIST_FOREACH(ccbh, &softc->pending_ccbs, periph_links.le)
973                         ccbh->ccb_state |= DA_CCB_RETRY_UA;
974                 splx(s);
975                 /* FALLTHROUGH*/
976         }
977         default:
978                 cam_periph_async(periph, code, path, arg);
979                 break;
980         }
981 }
982
983 static void
984 dasysctlinit(void *context, int pending)
985 {
986         struct cam_periph *periph;
987         struct da_softc *softc;
988         char tmpstr[80], tmpstr2[80];
989
990         periph = (struct cam_periph *)context;
991         softc = (struct da_softc *)periph->softc;
992
993         snprintf(tmpstr, sizeof(tmpstr), "CAM DA unit %d", periph->unit_number);
994         snprintf(tmpstr2, sizeof(tmpstr2), "%d", periph->unit_number);
995
996         mtx_lock(&Giant);
997         sysctl_ctx_init(&softc->sysctl_ctx);
998         softc->flags |= DA_FLAG_SCTX_INIT;
999         softc->sysctl_tree = SYSCTL_ADD_NODE(&softc->sysctl_ctx,
1000                 SYSCTL_STATIC_CHILDREN(_kern_cam_da), OID_AUTO, tmpstr2,
1001                 CTLFLAG_RD, 0, tmpstr);
1002         if (softc->sysctl_tree == NULL) {
1003                 printf("dasysctlinit: unable to allocate sysctl tree\n");
1004                 return;
1005         }
1006
1007         /*
1008          * Now register the sysctl handler, so the user can the value on
1009          * the fly.
1010          */
1011         SYSCTL_ADD_PROC(&softc->sysctl_ctx,SYSCTL_CHILDREN(softc->sysctl_tree),
1012                 OID_AUTO, "minimum_cmd_size", CTLTYPE_INT | CTLFLAG_RW,
1013                 &softc->minimum_cmd_size, 0, dacmdsizesysctl, "I",
1014                 "Minimum CDB size");
1015
1016         mtx_unlock(&Giant);
1017 }
1018
1019 static int
1020 dacmdsizesysctl(SYSCTL_HANDLER_ARGS)
1021 {
1022         int error, value;
1023
1024         value = *(int *)arg1;
1025
1026         error = sysctl_handle_int(oidp, &value, 0, req);
1027
1028         if ((error != 0)
1029          || (req->newptr == NULL))
1030                 return (error);
1031
1032         /*
1033          * Acceptable values here are 6, 10, 12 or 16.
1034          */
1035         if (value < 6)
1036                 value = 6;
1037         else if ((value > 6)
1038               && (value <= 10))
1039                 value = 10;
1040         else if ((value > 10)
1041               && (value <= 12))
1042                 value = 12;
1043         else if (value > 12)
1044                 value = 16;
1045
1046         *(int *)arg1 = value;
1047
1048         return (0);
1049 }
1050
1051 static cam_status
1052 daregister(struct cam_periph *periph, void *arg)
1053 {
1054         int s;
1055         struct da_softc *softc;
1056         struct ccb_setasync csa;
1057         struct ccb_pathinq cpi;
1058         struct ccb_getdev *cgd;
1059         char tmpstr[80];
1060         caddr_t match;
1061
1062         cgd = (struct ccb_getdev *)arg;
1063         if (periph == NULL) {
1064                 printf("daregister: periph was NULL!!\n");
1065                 return(CAM_REQ_CMP_ERR);
1066         }
1067
1068         if (cgd == NULL) {
1069                 printf("daregister: no getdev CCB, can't register device\n");
1070                 return(CAM_REQ_CMP_ERR);
1071         }
1072
1073         softc = (struct da_softc *)malloc(sizeof(*softc), M_DEVBUF,
1074             M_NOWAIT|M_ZERO);
1075
1076         if (softc == NULL) {
1077                 printf("daregister: Unable to probe new device. "
1078                        "Unable to allocate softc\n");                           
1079                 return(CAM_REQ_CMP_ERR);
1080         }
1081
1082         LIST_INIT(&softc->pending_ccbs);
1083         softc->state = DA_STATE_PROBE;
1084         bioq_init(&softc->bio_queue);
1085         if (SID_IS_REMOVABLE(&cgd->inq_data))
1086                 softc->flags |= DA_FLAG_PACK_REMOVABLE;
1087         if ((cgd->inq_data.flags & SID_CmdQue) != 0)
1088                 softc->flags |= DA_FLAG_TAGGED_QUEUING;
1089
1090         periph->softc = softc;
1091
1092         /*
1093          * See if this device has any quirks.
1094          */
1095         match = cam_quirkmatch((caddr_t)&cgd->inq_data,
1096                                (caddr_t)da_quirk_table,
1097                                sizeof(da_quirk_table)/sizeof(*da_quirk_table),
1098                                sizeof(*da_quirk_table), scsi_inquiry_match);
1099
1100         if (match != NULL)
1101                 softc->quirks = ((struct da_quirk_entry *)match)->quirks;
1102         else
1103                 softc->quirks = DA_Q_NONE;
1104
1105         /* Check if the SIM does not want 6 byte commands */
1106         xpt_setup_ccb(&cpi.ccb_h, periph->path, /*priority*/1);
1107         cpi.ccb_h.func_code = XPT_PATH_INQ;
1108         xpt_action((union ccb *)&cpi);
1109         if (cpi.ccb_h.status == CAM_REQ_CMP && (cpi.hba_misc & PIM_NO_6_BYTE))
1110                 softc->quirks |= DA_Q_NO_6_BYTE;
1111
1112         TASK_INIT(&softc->sysctl_task, 0, dasysctlinit, periph);
1113
1114         /*
1115          * RBC devices don't have to support READ(6), only READ(10).
1116          */
1117         if (softc->quirks & DA_Q_NO_6_BYTE || SID_TYPE(&cgd->inq_data) == T_RBC)
1118                 softc->minimum_cmd_size = 10;
1119         else
1120                 softc->minimum_cmd_size = 6;
1121
1122         /*
1123          * Load the user's default, if any.
1124          */
1125         snprintf(tmpstr, sizeof(tmpstr), "kern.cam.da.%d.minimum_cmd_size",
1126                  periph->unit_number);
1127         TUNABLE_INT_FETCH(tmpstr, &softc->minimum_cmd_size);
1128
1129         /*
1130          * 6, 10, 12 and 16 are the currently permissible values.
1131          */
1132         if (softc->minimum_cmd_size < 6)
1133                 softc->minimum_cmd_size = 6;
1134         else if ((softc->minimum_cmd_size > 6)
1135               && (softc->minimum_cmd_size <= 10))
1136                 softc->minimum_cmd_size = 10;
1137         else if ((softc->minimum_cmd_size > 10)
1138               && (softc->minimum_cmd_size <= 12))
1139                 softc->minimum_cmd_size = 12;
1140         else if (softc->minimum_cmd_size > 12)
1141                 softc->minimum_cmd_size = 16;
1142
1143         /*
1144          * Block our timeout handler while we
1145          * add this softc to the dev list.
1146          */
1147         s = splsoftclock();
1148         SLIST_INSERT_HEAD(&softc_list, softc, links);
1149         splx(s);
1150
1151         /*
1152          * Register this media as a disk
1153          */
1154
1155         softc->disk = disk_alloc();
1156         softc->disk->d_open = daopen;
1157         softc->disk->d_close = daclose;
1158         softc->disk->d_strategy = dastrategy;
1159         softc->disk->d_dump = dadump;
1160         softc->disk->d_name = "da";
1161         softc->disk->d_drv1 = periph;
1162         softc->disk->d_maxsize = DFLTPHYS; /* XXX: probably not arbitrary */
1163         softc->disk->d_unit = periph->unit_number;
1164         softc->disk->d_flags = DISKFLAG_NEEDSGIANT;
1165         disk_create(softc->disk, DISK_VERSION);
1166
1167         /*
1168          * Add async callbacks for bus reset and
1169          * bus device reset calls.  I don't bother
1170          * checking if this fails as, in most cases,
1171          * the system will function just fine without
1172          * them and the only alternative would be to
1173          * not attach the device on failure.
1174          */
1175         xpt_setup_ccb(&csa.ccb_h, periph->path, /*priority*/5);
1176         csa.ccb_h.func_code = XPT_SASYNC_CB;
1177         csa.event_enable = AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE;
1178         csa.callback = daasync;
1179         csa.callback_arg = periph;
1180         xpt_action((union ccb *)&csa);
1181         /*
1182          * Lock this peripheral until we are setup.
1183          * This first call can't block
1184          */
1185         (void)cam_periph_lock(periph, PRIBIO);
1186         xpt_schedule(periph, /*priority*/5);
1187
1188         return(CAM_REQ_CMP);
1189 }
1190
1191 static void
1192 dastart(struct cam_periph *periph, union ccb *start_ccb)
1193 {
1194         struct da_softc *softc;
1195
1196         softc = (struct da_softc *)periph->softc;
1197
1198         
1199         switch (softc->state) {
1200         case DA_STATE_NORMAL:
1201         {
1202                 /* Pull a buffer from the queue and get going on it */          
1203                 struct bio *bp;
1204                 int s;
1205
1206                 /*
1207                  * See if there is a buf with work for us to do..
1208                  */
1209                 s = splbio();
1210                 bp = bioq_first(&softc->bio_queue);
1211                 if (periph->immediate_priority <= periph->pinfo.priority) {
1212                         CAM_DEBUG_PRINT(CAM_DEBUG_SUBTRACE,
1213                                         ("queuing for immediate ccb\n"));
1214                         start_ccb->ccb_h.ccb_state = DA_CCB_WAITING;
1215                         SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h,
1216                                           periph_links.sle);
1217                         periph->immediate_priority = CAM_PRIORITY_NONE;
1218                         splx(s);
1219                         wakeup(&periph->ccb_list);
1220                 } else if (bp == NULL) {
1221                         splx(s);
1222                         xpt_release_ccb(start_ccb);
1223                 } else {
1224                         int oldspl;
1225                         u_int8_t tag_code;
1226
1227                         bioq_remove(&softc->bio_queue, bp);
1228
1229                         if ((softc->flags & DA_FLAG_NEED_OTAG) != 0) {
1230                                 softc->flags &= ~DA_FLAG_NEED_OTAG;
1231                                 softc->ordered_tag_count++;
1232                                 tag_code = MSG_ORDERED_Q_TAG;
1233                         } else {
1234                                 tag_code = MSG_SIMPLE_Q_TAG;
1235                         }
1236                         scsi_read_write(&start_ccb->csio,
1237                                         /*retries*/da_retry_count,
1238                                         /*cbfcnp*/dadone,
1239                                         /*tag_action*/tag_code,
1240                                         /*read_op*/bp->bio_cmd == BIO_READ,
1241                                         /*byte2*/0,
1242                                         softc->minimum_cmd_size,
1243                                         /*lba*/bp->bio_pblkno,
1244                                         /*block_count*/bp->bio_bcount /
1245                                         softc->params.secsize,
1246                                         /*data_ptr*/ bp->bio_data,
1247                                         /*dxfer_len*/ bp->bio_bcount,
1248                                         /*sense_len*/SSD_FULL_SIZE,
1249                                         /*timeout*/da_default_timeout*1000);
1250                         start_ccb->ccb_h.ccb_state = DA_CCB_BUFFER_IO;
1251
1252                         /*
1253                          * Block out any asyncronous callbacks
1254                          * while we touch the pending ccb list.
1255                          */
1256                         oldspl = splcam();
1257                         LIST_INSERT_HEAD(&softc->pending_ccbs,
1258                                          &start_ccb->ccb_h, periph_links.le);
1259                         softc->outstanding_cmds++;
1260                         splx(oldspl);
1261
1262                         /* We expect a unit attention from this device */
1263                         if ((softc->flags & DA_FLAG_RETRY_UA) != 0) {
1264                                 start_ccb->ccb_h.ccb_state |= DA_CCB_RETRY_UA;
1265                                 softc->flags &= ~DA_FLAG_RETRY_UA;
1266                         }
1267
1268                         start_ccb->ccb_h.ccb_bp = bp;
1269                         bp = bioq_first(&softc->bio_queue);
1270                         splx(s);
1271
1272                         xpt_action(start_ccb);
1273                 }
1274                 
1275                 if (bp != NULL) {
1276                         /* Have more work to do, so ensure we stay scheduled */
1277                         xpt_schedule(periph, /* XXX priority */1);
1278                 }
1279                 break;
1280         }
1281         case DA_STATE_PROBE:
1282         {
1283                 struct ccb_scsiio *csio;
1284                 struct scsi_read_capacity_data *rcap;
1285
1286                 rcap = (struct scsi_read_capacity_data *)malloc(sizeof(*rcap),
1287                                                                 M_TEMP,
1288                                                                 M_NOWAIT);
1289                 if (rcap == NULL) {
1290                         printf("dastart: Couldn't malloc read_capacity data\n");
1291                         /* da_free_periph??? */
1292                         break;
1293                 }
1294                 csio = &start_ccb->csio;
1295                 scsi_read_capacity(csio,
1296                                    /*retries*/4,
1297                                    dadone,
1298                                    MSG_SIMPLE_Q_TAG,
1299                                    rcap,
1300                                    SSD_FULL_SIZE,
1301                                    /*timeout*/5000);
1302                 start_ccb->ccb_h.ccb_bp = NULL;
1303                 start_ccb->ccb_h.ccb_state = DA_CCB_PROBE;
1304                 xpt_action(start_ccb);
1305                 break;
1306         }
1307         case DA_STATE_PROBE2:
1308         {
1309                 struct ccb_scsiio *csio;
1310                 struct scsi_read_capacity_data_long *rcaplong;
1311
1312                 rcaplong = (struct scsi_read_capacity_data_long *)
1313                         malloc(sizeof(*rcaplong), M_TEMP, M_NOWAIT);
1314                 if (rcaplong == NULL) {
1315                         printf("dastart: Couldn't malloc read_capacity data\n");
1316                         /* da_free_periph??? */
1317                         break;
1318                 }
1319                 csio = &start_ccb->csio;
1320                 scsi_read_capacity_16(csio,
1321                                       /*retries*/ 4,
1322                                       /*cbfcnp*/ dadone,
1323                                       /*tag_action*/ MSG_SIMPLE_Q_TAG,
1324                                       /*lba*/ 0,
1325                                       /*reladr*/ 0,
1326                                       /*pmi*/ 0,
1327                                       rcaplong,
1328                                       /*sense_len*/ SSD_FULL_SIZE,
1329                                       /*timeout*/ 60000);
1330                 start_ccb->ccb_h.ccb_bp = NULL;
1331                 start_ccb->ccb_h.ccb_state = DA_CCB_PROBE2;
1332                 xpt_action(start_ccb);  
1333                 break;
1334         }
1335         }
1336 }
1337
1338 static int
1339 cmd6workaround(union ccb *ccb)
1340 {
1341         struct scsi_rw_6 cmd6;
1342         struct scsi_rw_10 *cmd10;
1343         struct da_softc *softc;
1344         u_int8_t *cdb;
1345         int frozen;
1346
1347         cdb = ccb->csio.cdb_io.cdb_bytes;
1348
1349         /* Translation only possible if CDB is an array and cmd is R/W6 */
1350         if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0 ||
1351             (*cdb != READ_6 && *cdb != WRITE_6))
1352                 return 0;
1353
1354         xpt_print_path(ccb->ccb_h.path);
1355         printf("READ(6)/WRITE(6) not supported, "
1356                "increasing minimum_cmd_size to 10.\n");
1357         softc = (struct da_softc *)xpt_path_periph(ccb->ccb_h.path)->softc;
1358         softc->minimum_cmd_size = 10;
1359
1360         bcopy(cdb, &cmd6, sizeof(struct scsi_rw_6));
1361         cmd10 = (struct scsi_rw_10 *)cdb;
1362         cmd10->opcode = (cmd6.opcode == READ_6) ? READ_10 : WRITE_10;
1363         cmd10->byte2 = 0;
1364         scsi_ulto4b(scsi_3btoul(cmd6.addr), cmd10->addr);
1365         cmd10->reserved = 0;
1366         scsi_ulto2b(cmd6.length, cmd10->length);
1367         cmd10->control = cmd6.control;
1368         ccb->csio.cdb_len = sizeof(*cmd10);
1369
1370         /* Requeue request, unfreezing queue if necessary */
1371         frozen = (ccb->ccb_h.status & CAM_DEV_QFRZN) != 0;
1372         ccb->ccb_h.status = CAM_REQUEUE_REQ;
1373         xpt_action(ccb);
1374         if (frozen) {
1375                 cam_release_devq(ccb->ccb_h.path,
1376                                  /*relsim_flags*/0,
1377                                  /*reduction*/0,
1378                                  /*timeout*/0,
1379                                  /*getcount_only*/0);
1380         }
1381         return (ERESTART);
1382 }
1383
1384 static void
1385 dadone(struct cam_periph *periph, union ccb *done_ccb)
1386 {
1387         struct da_softc *softc;
1388         struct ccb_scsiio *csio;
1389
1390         softc = (struct da_softc *)periph->softc;
1391         csio = &done_ccb->csio;
1392         switch (csio->ccb_h.ccb_state & DA_CCB_TYPE_MASK) {
1393         case DA_CCB_BUFFER_IO:
1394         {
1395                 struct bio *bp;
1396                 int    oldspl;
1397
1398                 bp = (struct bio *)done_ccb->ccb_h.ccb_bp;
1399                 if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
1400                         int error;
1401                         int s;
1402                         int sf;
1403                         
1404                         if ((csio->ccb_h.ccb_state & DA_CCB_RETRY_UA) != 0)
1405                                 sf = SF_RETRY_UA;
1406                         else
1407                                 sf = 0;
1408
1409                         error = daerror(done_ccb, CAM_RETRY_SELTO, sf);
1410                         if (error == ERESTART) {
1411                                 /*
1412                                  * A retry was scheuled, so
1413                                  * just return.
1414                                  */
1415                                 return;
1416                         }
1417                         if (error != 0) {
1418
1419                                 s = splbio();
1420
1421                                 if (error == ENXIO) {
1422                                         /*
1423                                          * Catastrophic error.  Mark our pack as
1424                                          * invalid.
1425                                          */
1426                                         /* XXX See if this is really a media
1427                                          *     change first.
1428                                          */
1429                                         xpt_print_path(periph->path);
1430                                         printf("Invalidating pack\n");
1431                                         softc->flags |= DA_FLAG_PACK_INVALID;
1432                                 }
1433
1434                                 /*
1435                                  * return all queued I/O with EIO, so that
1436                                  * the client can retry these I/Os in the
1437                                  * proper order should it attempt to recover.
1438                                  */
1439                                 bioq_flush(&softc->bio_queue, NULL, EIO);
1440                                 splx(s);
1441                                 bp->bio_error = error;
1442                                 bp->bio_resid = bp->bio_bcount;
1443                                 bp->bio_flags |= BIO_ERROR;
1444                         } else {
1445                                 bp->bio_resid = csio->resid;
1446                                 bp->bio_error = 0;
1447                                 if (bp->bio_resid != 0)
1448                                         bp->bio_flags |= BIO_ERROR;
1449                         }
1450                         if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
1451                                 cam_release_devq(done_ccb->ccb_h.path,
1452                                                  /*relsim_flags*/0,
1453                                                  /*reduction*/0,
1454                                                  /*timeout*/0,
1455                                                  /*getcount_only*/0);
1456                 } else {
1457                         if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
1458                                 panic("REQ_CMP with QFRZN");
1459                         bp->bio_resid = csio->resid;
1460                         if (csio->resid > 0)
1461                                 bp->bio_flags |= BIO_ERROR;
1462                 }
1463
1464                 /*
1465                  * Block out any asyncronous callbacks
1466                  * while we touch the pending ccb list.
1467                  */
1468                 oldspl = splcam();
1469                 LIST_REMOVE(&done_ccb->ccb_h, periph_links.le);
1470                 softc->outstanding_cmds--;
1471                 if (softc->outstanding_cmds == 0)
1472                         softc->flags |= DA_FLAG_WENT_IDLE;
1473                 splx(oldspl);
1474
1475                 biodone(bp);
1476                 break;
1477         }
1478         case DA_CCB_PROBE:
1479         case DA_CCB_PROBE2:
1480         {
1481                 struct     scsi_read_capacity_data *rdcap;
1482                 struct     scsi_read_capacity_data_long *rcaplong;
1483                 char       announce_buf[80];
1484
1485                 rdcap = NULL;
1486                 rcaplong = NULL;
1487                 if (softc->state == DA_STATE_PROBE)
1488                         rdcap =(struct scsi_read_capacity_data *)csio->data_ptr;
1489                 else
1490                         rcaplong = (struct scsi_read_capacity_data_long *)
1491                                 csio->data_ptr;
1492
1493                 if ((csio->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
1494                         struct disk_params *dp;
1495                         uint32_t block_size;
1496                         uint64_t maxsector;
1497
1498                         if (softc->state == DA_STATE_PROBE) {
1499                                 block_size = scsi_4btoul(rdcap->length);
1500                                 maxsector = scsi_4btoul(rdcap->addr);
1501
1502                                 /*
1503                                  * According to SBC-2, if the standard 10
1504                                  * byte READ CAPACITY command returns 2^32,
1505                                  * we should issue the 16 byte version of
1506                                  * the command, since the device in question
1507                                  * has more sectors than can be represented
1508                                  * with the short version of the command.
1509                                  */
1510                                 if (maxsector == 0xffffffff) {
1511                                         softc->state = DA_STATE_PROBE2;
1512                                         free(rdcap, M_TEMP);
1513                                         xpt_release_ccb(done_ccb);
1514                                         xpt_schedule(periph, /*priority*/5);
1515                                         return;
1516                                 }
1517                         } else {
1518                                 block_size = scsi_4btoul(rcaplong->length);
1519                                 maxsector = scsi_8btou64(rcaplong->addr);
1520                         }
1521                         dasetgeom(periph, block_size, maxsector);
1522                         dp = &softc->params;
1523                         snprintf(announce_buf, sizeof(announce_buf),
1524                                 "%juMB (%ju %u byte sectors: %dH %dS/T %dC)",
1525                                 (uintmax_t) (((uintmax_t)dp->secsize *
1526                                 dp->sectors) / (1024*1024)),
1527                                 (uintmax_t)dp->sectors,
1528                                 dp->secsize, dp->heads, dp->secs_per_track,
1529                                 dp->cylinders);
1530                 } else {
1531                         int     error;
1532
1533                         announce_buf[0] = '\0';
1534
1535                         /*
1536                          * Retry any UNIT ATTENTION type errors.  They
1537                          * are expected at boot.
1538                          */
1539                         error = daerror(done_ccb, CAM_RETRY_SELTO,
1540                                         SF_RETRY_UA|SF_NO_PRINT);
1541                         if (error == ERESTART) {
1542                                 /*
1543                                  * A retry was scheuled, so
1544                                  * just return.
1545                                  */
1546                                 return;
1547                         } else if (error != 0) {
1548                                 struct scsi_sense_data *sense;
1549                                 int asc, ascq;
1550                                 int sense_key, error_code;
1551                                 int have_sense;
1552                                 cam_status status;
1553                                 struct ccb_getdev cgd;
1554
1555                                 /* Don't wedge this device's queue */
1556                                 status = done_ccb->ccb_h.status;
1557                                 if ((status & CAM_DEV_QFRZN) != 0)
1558                                         cam_release_devq(done_ccb->ccb_h.path,
1559                                                          /*relsim_flags*/0,
1560                                                          /*reduction*/0,
1561                                                          /*timeout*/0,
1562                                                          /*getcount_only*/0);
1563
1564
1565                                 xpt_setup_ccb(&cgd.ccb_h, 
1566                                               done_ccb->ccb_h.path,
1567                                               /* priority */ 1);
1568                                 cgd.ccb_h.func_code = XPT_GDEV_TYPE;
1569                                 xpt_action((union ccb *)&cgd);
1570
1571                                 if (((csio->ccb_h.flags & CAM_SENSE_PHYS) != 0)
1572                                  || ((csio->ccb_h.flags & CAM_SENSE_PTR) != 0)
1573                                  || ((status & CAM_AUTOSNS_VALID) == 0))
1574                                         have_sense = FALSE;
1575                                 else
1576                                         have_sense = TRUE;
1577
1578                                 if (have_sense) {
1579                                         sense = &csio->sense_data;
1580                                         scsi_extract_sense(sense, &error_code,
1581                                                            &sense_key, 
1582                                                            &asc, &ascq);
1583                                 }
1584                                 /*
1585                                  * Attach to anything that claims to be a
1586                                  * direct access or optical disk device,
1587                                  * as long as it doesn't return a "Logical
1588                                  * unit not supported" (0x25) error.
1589                                  */
1590                                 if ((have_sense) && (asc != 0x25)
1591                                  && (error_code == SSD_CURRENT_ERROR)) {
1592                                         const char *sense_key_desc;
1593                                         const char *asc_desc;
1594
1595                                         scsi_sense_desc(sense_key, asc, ascq,
1596                                                         &cgd.inq_data,
1597                                                         &sense_key_desc,
1598                                                         &asc_desc);
1599                                         snprintf(announce_buf,
1600                                             sizeof(announce_buf),
1601                                                 "Attempt to query device "
1602                                                 "size failed: %s, %s",
1603                                                 sense_key_desc,
1604                                                 asc_desc);
1605                                 } else { 
1606                                         if (have_sense)
1607                                                 scsi_sense_print(
1608                                                         &done_ccb->csio);
1609                                         else {
1610                                                 xpt_print_path(periph->path);
1611                                                 printf("got CAM status %#x\n",
1612                                                        done_ccb->ccb_h.status);
1613                                         }
1614
1615                                         xpt_print_path(periph->path);
1616                                         printf("fatal error, failed" 
1617                                                " to attach to device\n");
1618
1619                                         /*
1620                                          * Free up resources.
1621                                          */
1622                                         cam_periph_invalidate(periph);
1623                                 } 
1624                         }
1625                 }
1626                 free(csio->data_ptr, M_TEMP);
1627                 if (announce_buf[0] != '\0') {
1628                         xpt_announce_periph(periph, announce_buf);
1629                         /*
1630                          * Create our sysctl variables, now that we know
1631                          * we have successfully attached.
1632                          */
1633                         taskqueue_enqueue(taskqueue_thread,&softc->sysctl_task);
1634                 }
1635                 softc->state = DA_STATE_NORMAL; 
1636                 /*
1637                  * Since our peripheral may be invalidated by an error
1638                  * above or an external event, we must release our CCB
1639                  * before releasing the probe lock on the peripheral.
1640                  * The peripheral will only go away once the last lock
1641                  * is removed, and we need it around for the CCB release
1642                  * operation.
1643                  */
1644                 xpt_release_ccb(done_ccb);
1645                 cam_periph_unlock(periph);
1646                 return;
1647         }
1648         case DA_CCB_WAITING:
1649         {
1650                 /* Caller will release the CCB */
1651                 wakeup(&done_ccb->ccb_h.cbfcnp);
1652                 return;
1653         }
1654         case DA_CCB_DUMP:
1655                 /* No-op.  We're polling */
1656                 return;
1657         default:
1658                 break;
1659         }
1660         xpt_release_ccb(done_ccb);
1661 }
1662
1663 static int
1664 daerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
1665 {
1666         struct da_softc   *softc;
1667         struct cam_periph *periph;
1668         int error;
1669
1670         periph = xpt_path_periph(ccb->ccb_h.path);
1671         softc = (struct da_softc *)periph->softc;
1672
1673         /*
1674          * Automatically detect devices that do not support
1675          * READ(6)/WRITE(6) and upgrade to using 10 byte cdbs.
1676          */
1677         error = 0;
1678         if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INVALID) {
1679                 error = cmd6workaround(ccb);
1680         } else if (((ccb->ccb_h.status & CAM_STATUS_MASK) ==
1681                    CAM_SCSI_STATUS_ERROR)
1682          && (ccb->ccb_h.status & CAM_AUTOSNS_VALID)
1683          && (ccb->csio.scsi_status == SCSI_STATUS_CHECK_COND)
1684          && ((ccb->ccb_h.flags & CAM_SENSE_PHYS) == 0)
1685          && ((ccb->ccb_h.flags & CAM_SENSE_PTR) == 0)) {
1686                 int sense_key, error_code, asc, ascq;
1687
1688                 scsi_extract_sense(&ccb->csio.sense_data,
1689                                    &error_code, &sense_key, &asc, &ascq);
1690                 if (sense_key == SSD_KEY_ILLEGAL_REQUEST)
1691                         error = cmd6workaround(ccb);
1692         }
1693         if (error == ERESTART)
1694                 return (ERESTART);
1695
1696         /*
1697          * XXX
1698          * Until we have a better way of doing pack validation,
1699          * don't treat UAs as errors.
1700          */
1701         sense_flags |= SF_RETRY_UA;
1702         return(cam_periph_error(ccb, cam_flags, sense_flags,
1703                                 &softc->saved_ccb));
1704 }
1705
1706 static void
1707 daprevent(struct cam_periph *periph, int action)
1708 {
1709         struct  da_softc *softc;
1710         union   ccb *ccb;               
1711         int     error;
1712                 
1713         softc = (struct da_softc *)periph->softc;
1714
1715         if (((action == PR_ALLOW)
1716           && (softc->flags & DA_FLAG_PACK_LOCKED) == 0)
1717          || ((action == PR_PREVENT)
1718           && (softc->flags & DA_FLAG_PACK_LOCKED) != 0)) {
1719                 return;
1720         }
1721
1722         ccb = cam_periph_getccb(periph, /*priority*/1);
1723
1724         scsi_prevent(&ccb->csio,
1725                      /*retries*/1,
1726                      /*cbcfp*/dadone,
1727                      MSG_SIMPLE_Q_TAG,
1728                      action,
1729                      SSD_FULL_SIZE,
1730                      5000);
1731
1732         error = cam_periph_runccb(ccb, /*error_routine*/NULL, CAM_RETRY_SELTO,
1733                                   SF_RETRY_UA, softc->disk->d_devstat);
1734
1735         if (error == 0) {
1736                 if (action == PR_ALLOW)
1737                         softc->flags &= ~DA_FLAG_PACK_LOCKED;
1738                 else
1739                         softc->flags |= DA_FLAG_PACK_LOCKED;
1740         }
1741
1742         xpt_release_ccb(ccb);
1743 }
1744
1745 static int
1746 dagetcapacity(struct cam_periph *periph)
1747 {
1748         struct da_softc *softc;
1749         union ccb *ccb;
1750         struct scsi_read_capacity_data *rcap;
1751         struct scsi_read_capacity_data_long *rcaplong;
1752         uint32_t block_len;
1753         uint64_t maxsector;
1754         int error;
1755
1756         softc = (struct da_softc *)periph->softc;
1757         block_len = 0;
1758         maxsector = 0;
1759         error = 0;
1760
1761         /* Do a read capacity */
1762         rcap = (struct scsi_read_capacity_data *)malloc(sizeof(*rcaplong),
1763                                                         M_TEMP,
1764                                                         M_WAITOK);
1765                 
1766         ccb = cam_periph_getccb(periph, /*priority*/1);
1767         scsi_read_capacity(&ccb->csio,
1768                            /*retries*/4,
1769                            /*cbfncp*/dadone,
1770                            MSG_SIMPLE_Q_TAG,
1771                            rcap,
1772                            SSD_FULL_SIZE,
1773                            /*timeout*/60000);
1774         ccb->ccb_h.ccb_bp = NULL;
1775
1776         error = cam_periph_runccb(ccb, daerror,
1777                                   /*cam_flags*/CAM_RETRY_SELTO,
1778                                   /*sense_flags*/SF_RETRY_UA,
1779                                   softc->disk->d_devstat);
1780
1781         if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
1782                 cam_release_devq(ccb->ccb_h.path,
1783                                  /*relsim_flags*/0,
1784                                  /*reduction*/0,
1785                                  /*timeout*/0,
1786                                  /*getcount_only*/0);
1787
1788         if (error == 0) {
1789                 block_len = scsi_4btoul(rcap->length);
1790                 maxsector = scsi_4btoul(rcap->addr);
1791
1792                 if (maxsector != 0xffffffff)
1793                         goto done;
1794         } else
1795                 goto done;
1796
1797         rcaplong = (struct scsi_read_capacity_data_long *)rcap;
1798
1799         scsi_read_capacity_16(&ccb->csio,
1800                               /*retries*/ 4,
1801                               /*cbfcnp*/ dadone,
1802                               /*tag_action*/ MSG_SIMPLE_Q_TAG,
1803                               /*lba*/ 0,
1804                               /*reladr*/ 0,
1805                               /*pmi*/ 0,
1806                               rcaplong,
1807                               /*sense_len*/ SSD_FULL_SIZE,
1808                               /*timeout*/ 60000);
1809         ccb->ccb_h.ccb_bp = NULL;
1810
1811         error = cam_periph_runccb(ccb, daerror,
1812                                   /*cam_flags*/CAM_RETRY_SELTO,
1813                                   /*sense_flags*/SF_RETRY_UA,
1814                                   softc->disk->d_devstat);
1815
1816         if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
1817                 cam_release_devq(ccb->ccb_h.path,
1818                                  /*relsim_flags*/0,
1819                                  /*reduction*/0,
1820                                  /*timeout*/0,
1821                                  /*getcount_only*/0);
1822
1823         if (error == 0) {
1824                 block_len = scsi_4btoul(rcaplong->length);
1825                 maxsector = scsi_8btou64(rcaplong->addr);
1826         }
1827
1828 done:
1829
1830         if (error == 0)
1831                 dasetgeom(periph, block_len, maxsector);
1832
1833         xpt_release_ccb(ccb);
1834
1835         free(rcap, M_TEMP);
1836
1837         return (error);
1838 }
1839
1840 static void
1841 dasetgeom(struct cam_periph *periph, uint32_t block_len, uint64_t maxsector)
1842 {
1843         struct ccb_calc_geometry ccg;
1844         struct da_softc *softc;
1845         struct disk_params *dp;
1846
1847         softc = (struct da_softc *)periph->softc;
1848
1849         dp = &softc->params;
1850         dp->secsize = block_len;
1851         dp->sectors = maxsector + 1;
1852         /*
1853          * Have the controller provide us with a geometry
1854          * for this disk.  The only time the geometry
1855          * matters is when we boot and the controller
1856          * is the only one knowledgeable enough to come
1857          * up with something that will make this a bootable
1858          * device.
1859          */
1860         xpt_setup_ccb(&ccg.ccb_h, periph->path, /*priority*/1);
1861         ccg.ccb_h.func_code = XPT_CALC_GEOMETRY;
1862         ccg.block_size = dp->secsize;
1863         ccg.volume_size = dp->sectors;
1864         ccg.heads = 0;
1865         ccg.secs_per_track = 0;
1866         ccg.cylinders = 0;
1867         xpt_action((union ccb*)&ccg);
1868         if ((ccg.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
1869                 /*
1870                  * We don't know what went wrong here- but just pick
1871                  * a geometry so we don't have nasty things like divide
1872                  * by zero.
1873                  */
1874                 dp->heads = 255;
1875                 dp->secs_per_track = 255;
1876                 dp->cylinders = dp->sectors / (255 * 255);
1877                 if (dp->cylinders == 0) {
1878                         dp->cylinders = 1;
1879                 }
1880         } else {
1881                 dp->heads = ccg.heads;
1882                 dp->secs_per_track = ccg.secs_per_track;
1883                 dp->cylinders = ccg.cylinders;
1884         }
1885 }
1886
1887 static void
1888 dasendorderedtag(void *arg)
1889 {
1890         struct da_softc *softc;
1891         int s;
1892
1893         for (softc = SLIST_FIRST(&softc_list);
1894              softc != NULL;
1895              softc = SLIST_NEXT(softc, links)) {
1896                 s = splsoftcam();
1897                 if ((softc->ordered_tag_count == 0) 
1898                  && ((softc->flags & DA_FLAG_WENT_IDLE) == 0)) {
1899                         softc->flags |= DA_FLAG_NEED_OTAG;
1900                 }
1901                 if (softc->outstanding_cmds > 0)
1902                         softc->flags &= ~DA_FLAG_WENT_IDLE;
1903
1904                 softc->ordered_tag_count = 0;
1905                 splx(s);
1906         }
1907         /* Queue us up again */
1908         timeout(dasendorderedtag, NULL,
1909                 (da_default_timeout * hz) / DA_ORDEREDTAG_INTERVAL);
1910 }
1911
1912 /*
1913  * Step through all DA peripheral drivers, and if the device is still open,
1914  * sync the disk cache to physical media.
1915  */
1916 static void
1917 dashutdown(void * arg, int howto)
1918 {
1919         struct cam_periph *periph;
1920         struct da_softc *softc;
1921
1922         TAILQ_FOREACH(periph, &dadriver.units, unit_links) {
1923                 union ccb ccb;
1924                 softc = (struct da_softc *)periph->softc;
1925
1926                 /*
1927                  * We only sync the cache if the drive is still open, and
1928                  * if the drive is capable of it..
1929                  */
1930                 if (((softc->flags & DA_FLAG_OPEN) == 0)
1931                  || (softc->quirks & DA_Q_NO_SYNC_CACHE))
1932                         continue;
1933
1934                 xpt_setup_ccb(&ccb.ccb_h, periph->path, /*priority*/1);
1935
1936                 ccb.ccb_h.ccb_state = DA_CCB_DUMP;
1937                 scsi_synchronize_cache(&ccb.csio,
1938                                        /*retries*/1,
1939                                        /*cbfcnp*/dadone,
1940                                        MSG_SIMPLE_Q_TAG,
1941                                        /*begin_lba*/0, /* whole disk */
1942                                        /*lb_count*/0,
1943                                        SSD_FULL_SIZE,
1944                                        60 * 60 * 1000);
1945
1946                 xpt_polled_action(&ccb);
1947
1948                 if ((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
1949                         if (((ccb.ccb_h.status & CAM_STATUS_MASK) ==
1950                              CAM_SCSI_STATUS_ERROR)
1951                          && (ccb.csio.scsi_status == SCSI_STATUS_CHECK_COND)){
1952                                 int error_code, sense_key, asc, ascq;
1953
1954                                 scsi_extract_sense(&ccb.csio.sense_data,
1955                                                    &error_code, &sense_key,
1956                                                    &asc, &ascq);
1957
1958                                 if (sense_key != SSD_KEY_ILLEGAL_REQUEST)
1959                                         scsi_sense_print(&ccb.csio);
1960                         } else {
1961                                 xpt_print_path(periph->path);
1962                                 printf("Synchronize cache failed, status "
1963                                        "== 0x%x, scsi status == 0x%x\n",
1964                                        ccb.ccb_h.status, ccb.csio.scsi_status);
1965                         }
1966                 }
1967
1968                 if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0)
1969                         cam_release_devq(ccb.ccb_h.path,
1970                                          /*relsim_flags*/0,
1971                                          /*reduction*/0,
1972                                          /*timeout*/0,
1973                                          /*getcount_only*/0);
1974
1975         }
1976 }
1977
1978 #else /* !_KERNEL */
1979
1980 /*
1981  * XXX This is only left out of the kernel build to silence warnings.  If,
1982  * for some reason this function is used in the kernel, the ifdefs should
1983  * be moved so it is included both in the kernel and userland.
1984  */
1985 void
1986 scsi_format_unit(struct ccb_scsiio *csio, u_int32_t retries,
1987                  void (*cbfcnp)(struct cam_periph *, union ccb *),
1988                  u_int8_t tag_action, u_int8_t byte2, u_int16_t ileave,
1989                  u_int8_t *data_ptr, u_int32_t dxfer_len, u_int8_t sense_len,
1990                  u_int32_t timeout)
1991 {
1992         struct scsi_format_unit *scsi_cmd;
1993
1994         scsi_cmd = (struct scsi_format_unit *)&csio->cdb_io.cdb_bytes;
1995         scsi_cmd->opcode = FORMAT_UNIT;
1996         scsi_cmd->byte2 = byte2;
1997         scsi_ulto2b(ileave, scsi_cmd->interleave);
1998
1999         cam_fill_csio(csio,
2000                       retries,
2001                       cbfcnp,
2002                       /*flags*/ (dxfer_len > 0) ? CAM_DIR_OUT : CAM_DIR_NONE,
2003                       tag_action,
2004                       data_ptr,
2005                       dxfer_len,
2006                       sense_len,
2007                       sizeof(*scsi_cmd),
2008                       timeout);
2009 }
2010
2011 #endif /* _KERNEL */