[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/cam/scsi/scsi_da.c

Version: -  FREEBSD  -  FREEBSD7  -  FREEBSD71  -  FREEBSD70  -  FREEBSD6  -  FREEBSD64  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  OPENSOLARIS  -  minix-3-1-1  -  TRUSTEDBSD-SEBSD  -  FREEBSD-LIBC  -  FREEBSD7-LIBC  -  FREEBSD6-LIBC  -  GLIBC27 
SearchContext: -  none  -  excerpts  -  bigexcerpts 

  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: src/sys/cam/scsi/scsi_da.c,v 1.232 2008/12/23 09:11:05 remko Exp $");
 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 #include <sys/lock.h>
 41 #include <sys/mutex.h>
 42 #include <sys/conf.h>
 43 #include <sys/devicestat.h>
 44 #include <sys/eventhandler.h>
 45 #include <sys/malloc.h>
 46 #include <sys/cons.h>
 47 #include <geom/geom_disk.h>
 48 #endif /* _KERNEL */
 49 
 50 #ifndef _KERNEL
 51 #include <stdio.h>
 52 #include <string.h>
 53 #endif /* _KERNEL */
 54 
 55 #include <cam/cam.h>
 56 #include <cam/cam_ccb.h>
 57 #include <cam/cam_periph.h>
 58 #include <cam/cam_xpt_periph.h>
 59 #include <cam/cam_sim.h>
 60 
 61 #include <cam/scsi/scsi_message.h>
 62 
 63 #ifndef _KERNEL 
 64 #include <cam/scsi/scsi_da.h>
 65 #endif /* !_KERNEL */
 66 
 67 #ifdef _KERNEL
 68 typedef enum {
 69         DA_STATE_PROBE,
 70         DA_STATE_PROBE2,
 71         DA_STATE_NORMAL
 72 } da_state;
 73 
 74 typedef enum {
 75         DA_FLAG_PACK_INVALID    = 0x001,
 76         DA_FLAG_NEW_PACK        = 0x002,
 77         DA_FLAG_PACK_LOCKED     = 0x004,
 78         DA_FLAG_PACK_REMOVABLE  = 0x008,
 79         DA_FLAG_TAGGED_QUEUING  = 0x010,
 80         DA_FLAG_NEED_OTAG       = 0x020,
 81         DA_FLAG_WENT_IDLE       = 0x040,
 82         DA_FLAG_RETRY_UA        = 0x080,
 83         DA_FLAG_OPEN            = 0x100,
 84         DA_FLAG_SCTX_INIT       = 0x200
 85 } da_flags;
 86 
 87 typedef enum {
 88         DA_Q_NONE               = 0x00,
 89         DA_Q_NO_SYNC_CACHE      = 0x01,
 90         DA_Q_NO_6_BYTE          = 0x02,
 91         DA_Q_NO_PREVENT         = 0x04
 92 } da_quirks;
 93 
 94 typedef enum {
 95         DA_CCB_PROBE            = 0x01,
 96         DA_CCB_PROBE2           = 0x02,
 97         DA_CCB_BUFFER_IO        = 0x03,
 98         DA_CCB_WAITING          = 0x04,
 99         DA_CCB_DUMP             = 0x05,
100         DA_CCB_TYPE_MASK        = 0x0F,
101         DA_CCB_RETRY_UA         = 0x10
102 } da_ccb_state;
103 
104 /* Offsets into our private area for storing information */
105 #define ccb_state       ppriv_field0
106 #define ccb_bp          ppriv_ptr1
107 
108 struct disk_params {
109         u_int8_t  heads;
110         u_int32_t cylinders;
111         u_int8_t  secs_per_track;
112         u_int32_t secsize;      /* Number of bytes/sector */
113         u_int64_t sectors;      /* total number sectors */
114 };
115 
116 struct da_softc {
117         struct   bio_queue_head bio_queue;
118         SLIST_ENTRY(da_softc) links;
119         LIST_HEAD(, ccb_hdr) pending_ccbs;
120         da_state state;
121         da_flags flags; 
122         da_quirks quirks;
123         int      minimum_cmd_size;
124         int      ordered_tag_count;
125         int      outstanding_cmds;
126         struct   disk_params params;
127         struct   disk *disk;
128         union    ccb saved_ccb;
129         struct task             sysctl_task;
130         struct sysctl_ctx_list  sysctl_ctx;
131         struct sysctl_oid       *sysctl_tree;
132         struct callout          sendordered_c;
133 };
134 
135 struct da_quirk_entry {
136         struct scsi_inquiry_pattern inq_pat;
137         da_quirks quirks;
138 };
139 
140 static const char quantum[] = "QUANTUM";
141 static const char microp[] = "MICROP";
142 
143 static struct da_quirk_entry da_quirk_table[] =
144 {
145         /* SPI, FC devices */
146         {
147                 /*
148                  * Fujitsu M2513A MO drives.
149                  * Tested devices: M2513A2 firmware versions 1200 & 1300.
150                  * (dip switch selects whether T_DIRECT or T_OPTICAL device)
151                  * Reported by: W.Scholten <whs@xs4all.nl>
152                  */
153                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "FUJITSU", "M2513A", "*"},
154                 /*quirks*/ DA_Q_NO_SYNC_CACHE
155         },
156         {
157                 /* See above. */
158                 {T_OPTICAL, SIP_MEDIA_REMOVABLE, "FUJITSU", "M2513A", "*"},
159                 /*quirks*/ DA_Q_NO_SYNC_CACHE
160         },
161         {
162                 /*
163                  * This particular Fujitsu drive doesn't like the
164                  * synchronize cache command.
165                  * Reported by: Tom Jackson <toj@gorilla.net>
166                  */
167                 {T_DIRECT, SIP_MEDIA_FIXED, "FUJITSU", "M2954*", "*"},
168                 /*quirks*/ DA_Q_NO_SYNC_CACHE
169         },
170         {
171                 /*
172                  * This drive doesn't like the synchronize cache command
173                  * either.  Reported by: Matthew Jacob <mjacob@feral.com>
174                  * in NetBSD PR kern/6027, August 24, 1998.
175                  */
176                 {T_DIRECT, SIP_MEDIA_FIXED, microp, "2217*", "*"},
177                 /*quirks*/ DA_Q_NO_SYNC_CACHE
178         },
179         {
180                 /*
181                  * This drive doesn't like the synchronize cache command
182                  * either.  Reported by: Hellmuth Michaelis (hm@kts.org)
183                  * (PR 8882).
184                  */
185                 {T_DIRECT, SIP_MEDIA_FIXED, microp, "2112*", "*"},
186                 /*quirks*/ DA_Q_NO_SYNC_CACHE
187         },
188         {
189                 /*
190                  * Doesn't like the synchronize cache command.
191                  * Reported by: Blaz Zupan <blaz@gold.amis.net>
192                  */
193                 {T_DIRECT, SIP_MEDIA_FIXED, "NEC", "D3847*", "*"},
194                 /*quirks*/ DA_Q_NO_SYNC_CACHE
195         },
196         {
197                 /*
198                  * Doesn't like the synchronize cache command.
199                  * Reported by: Blaz Zupan <blaz@gold.amis.net>
200                  */
201                 {T_DIRECT, SIP_MEDIA_FIXED, quantum, "MAVERICK 540S", "*"},
202                 /*quirks*/ DA_Q_NO_SYNC_CACHE
203         },
204         {
205                 /*
206                  * Doesn't like the synchronize cache command.
207                  */
208                 {T_DIRECT, SIP_MEDIA_FIXED, quantum, "LPS525S", "*"},
209                 /*quirks*/ DA_Q_NO_SYNC_CACHE
210         },
211         {
212                 /*
213                  * Doesn't like the synchronize cache command.
214                  * Reported by: walter@pelissero.de
215                  */
216                 {T_DIRECT, SIP_MEDIA_FIXED, quantum, "LPS540S", "*"},
217                 /*quirks*/ DA_Q_NO_SYNC_CACHE
218         },
219         {
220                 /*
221                  * Doesn't work correctly with 6 byte reads/writes.
222                  * Returns illegal request, and points to byte 9 of the
223                  * 6-byte CDB.
224                  * Reported by:  Adam McDougall <bsdx@spawnet.com>
225                  */
226                 {T_DIRECT, SIP_MEDIA_FIXED, quantum, "VIKING 4*", "*"},
227                 /*quirks*/ DA_Q_NO_6_BYTE
228         },
229         {
230                 /* See above. */
231                 {T_DIRECT, SIP_MEDIA_FIXED, quantum, "VIKING 2*", "*"},
232                 /*quirks*/ DA_Q_NO_6_BYTE
233         },
234         {
235                 /*
236                  * Doesn't like the synchronize cache command.
237                  * Reported by: walter@pelissero.de
238                  */
239                 {T_DIRECT, SIP_MEDIA_FIXED, "CONNER", "CP3500*", "*"},
240                 /*quirks*/ DA_Q_NO_SYNC_CACHE
241         },
242         {
243                 /*
244                  * The CISS RAID controllers do not support SYNC_CACHE
245                  */
246                 {T_DIRECT, SIP_MEDIA_FIXED, "COMPAQ", "RAID*", "*"},
247                 /*quirks*/ DA_Q_NO_SYNC_CACHE
248         },
249         /* USB mass storage devices supported by umass(4) */
250         {
251                 /*
252                  * EXATELECOM (Sigmatel) i-Bead 100/105 USB Flash MP3 Player
253                  * PR: kern/51675
254                  */
255                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "EXATEL", "i-BEAD10*", "*"},
256                 /*quirks*/ DA_Q_NO_SYNC_CACHE
257         },
258         {
259                 /*
260                  * Power Quotient Int. (PQI) USB flash key
261                  * PR: kern/53067
262                  */
263                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "Generic*", "USB Flash Disk*",
264                 "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
265         },
266         {
267                 /*
268                  * Creative Nomad MUVO mp3 player (USB)
269                  * PR: kern/53094
270                  */
271                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "CREATIVE", "NOMAD_MUVO", "*"},
272                 /*quirks*/ DA_Q_NO_SYNC_CACHE|DA_Q_NO_PREVENT
273         },
274         {
275                 /*
276                  * Jungsoft NEXDISK USB flash key
277                  * PR: kern/54737
278                  */
279                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "JUNGSOFT", "NEXDISK*", "*"},
280                 /*quirks*/ DA_Q_NO_SYNC_CACHE
281         },
282         {
283                 /*
284                  * FreeDik USB Mini Data Drive
285                  * PR: kern/54786
286                  */
287                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "FreeDik*", "Mini Data Drive",
288                 "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
289         },
290         {
291                 /*
292                  * Sigmatel USB Flash MP3 Player
293                  * PR: kern/57046
294                  */
295                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "SigmaTel", "MSCN", "*"},
296                 /*quirks*/ DA_Q_NO_SYNC_CACHE|DA_Q_NO_PREVENT
297         },
298         {
299                 /*
300                  * Neuros USB Digital Audio Computer
301                  * PR: kern/63645
302                  */
303                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "NEUROS", "dig. audio comp.",
304                 "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
305         },
306         {
307                 /*
308                  * SEAGRAND NP-900 MP3 Player
309                  * PR: kern/64563
310                  */
311                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "SEAGRAND", "NP-900*", "*"},
312                 /*quirks*/ DA_Q_NO_SYNC_CACHE|DA_Q_NO_PREVENT
313         },
314         {
315                 /*
316                  * iRiver iFP MP3 player (with UMS Firmware)
317                  * PR: kern/54881, i386/63941, kern/66124
318                  */
319                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "iRiver", "iFP*", "*"},
320                 /*quirks*/ DA_Q_NO_SYNC_CACHE
321         },
322         {
323                 /*
324                  * Frontier Labs NEX IA+ Digital Audio Player, rev 1.10/0.01
325                  * PR: kern/70158
326                  */
327                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "FL" , "Nex*", "*"},
328                 /*quirks*/ DA_Q_NO_SYNC_CACHE
329         },
330         {
331                 /*
332                  * ZICPlay USB MP3 Player with FM
333                  * PR: kern/75057
334                  */
335                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "ACTIONS*" , "USB DISK*", "*"},
336                 /*quirks*/ DA_Q_NO_SYNC_CACHE
337         },
338         {
339                 /*
340                  * TEAC USB floppy mechanisms
341                  */
342                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "TEAC" , "FD-05*", "*"},
343                 /*quirks*/ DA_Q_NO_SYNC_CACHE
344         },
345         {
346                 /*
347                  * Kingston DataTraveler II+ USB Pen-Drive.
348                  * Reported by: Pawel Jakub Dawidek <pjd@FreeBSD.org>
349                  */
350                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "Kingston" , "DataTraveler II+",
351                 "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
352         },
353         {
354                 /*
355                  * Motorola E398 Mobile Phone (TransFlash memory card).
356                  * Reported by: Wojciech A. Koszek <dunstan@FreeBSD.czest.pl>
357                  * PR: usb/89889
358                  */
359                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "Motorola" , "Motorola Phone",
360                 "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
361         },
362         {
363                 /*
364                  * Qware BeatZkey! Pro
365                  * PR: usb/79164
366                  */
367                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "GENERIC", "USB DISK DEVICE",
368                 "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
369         },
370         {
371                 /*
372                  * Time DPA20B 1GB MP3 Player
373                  * PR: usb/81846
374                  */
375                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "USB2.0*", "(FS) FLASH DISK*",
376                 "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
377         },
378         {
379                 /*
380                  * Samsung USB key 128Mb
381                  * PR: usb/90081
382                  */
383                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "USB-DISK", "FreeDik-FlashUsb",
384                 "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
385         },
386         {
387                 /*
388                  * Kingston DataTraveler 2.0 USB Flash memory.
389                  * PR: usb/89196
390                  */
391                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "Kingston", "DataTraveler 2.0",
392                 "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
393         },
394         {
395                 /*
396                  * Creative MUVO Slim mp3 player (USB)
397                  * PR: usb/86131
398                  */
399                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "CREATIVE", "MuVo Slim",
400                 "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE|DA_Q_NO_PREVENT
401                 },
402         {
403                 /*
404                  * United MP5512 Portable MP3 Player (2-in-1 USB DISK/MP3)
405                  * PR: usb/80487
406                  */
407                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "Generic*", "MUSIC DISK",
408                 "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
409         },
410         {
411                 /*
412                  * SanDisk Micro Cruzer 128MB
413                  * PR: usb/75970
414                  */
415                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "SanDisk" , "Micro Cruzer",
416                 "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
417         },
418         {
419                 /*
420                  * TOSHIBA TransMemory USB sticks
421                  * PR: kern/94660
422                  */
423                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "TOSHIBA", "TransMemory",
424                 "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
425         },
426         {
427                 /*
428                  * PNY USB Flash keys
429                  * PR: usb/75578, usb/72344, usb/65436 
430                  */
431                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "*" , "USB DISK*",
432                 "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
433         },
434         {
435                 /*
436                  * Genesys 6-in-1 Card Reader
437                  * PR: usb/94647
438                  */
439                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "Generic*", "STORAGE DEVICE*",
440                 "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
441         },
442         {
443                 /*
444                  * Rekam Digital CAMERA
445                  * PR: usb/98713
446                  */
447                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "CAMERA*", "4MP-9J6*",
448                 "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
449         },
450         {
451                 /*
452                  * iRiver H10 MP3 player
453                  * PR: usb/102547
454                  */
455                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "iriver", "H10*",
456                 "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
457         },
458         {
459                 /*
460                  * iRiver U10 MP3 player
461                  * PR: usb/92306
462                  */
463                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "iriver", "U10*",
464                 "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
465         },
466         {
467                 /*
468                  * X-Micro Flash Disk
469                  * PR: usb/96901
470                  */
471                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "X-Micro", "Flash Disk",
472                 "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
473         },
474         {
475                 /*
476                  * EasyMP3 EM732X USB 2.0 Flash MP3 Player
477                  * PR: usb/96546
478                  */
479                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "EM732X", "MP3 Player*",
480                 "1.00"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
481         },
482         {
483                 /*
484                  * Denver MP3 player
485                  * PR: usb/107101
486                  */
487                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "DENVER", "MP3 PLAYER",
488                  "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
489         },
490         {
491                 /*
492                  * Philips USB Key Audio KEY013
493                  * PR: usb/68412
494                  */
495                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "PHILIPS", "Key*", "*"},
496                 /*quirks*/ DA_Q_NO_SYNC_CACHE | DA_Q_NO_PREVENT
497         },
498         {
499                 /*
500                  * JNC MP3 Player
501                  * PR: usb/94439
502                  */
503                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "JNC*" , "MP3 Player*",
504                  "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
505         },
506         {
507                 /*
508                  * SAMSUNG MP0402H
509                  * PR: usb/108427
510                  */
511                 {T_DIRECT, SIP_MEDIA_FIXED, "SAMSUNG", "MP0402H", "*"},
512                 /*quirks*/ DA_Q_NO_SYNC_CACHE
513         },
514         {
515                 /*
516                  * I/O Magic USB flash - Giga Bank
517                  * PR: usb/108810
518                  */
519                 {T_DIRECT, SIP_MEDIA_FIXED, "GS-Magic", "stor*", "*"},
520                 /*quirks*/ DA_Q_NO_SYNC_CACHE
521         },
522         {
523                 /*
524                  * JoyFly 128mb USB Flash Drive
525                  * PR: 96133
526                  */
527                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "USB 2.0", "Flash Disk*",
528                  "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
529         },
530         {
531                 /*
532                  * ChipsBnk usb stick
533                  * PR: 103702
534                  */
535                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "ChipsBnk", "USB*",
536                  "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
537         },
538         {
539                 /*
540                  * Storcase (Kingston) InfoStation IFS FC2/SATA-R 201A
541                  * PR: 129858
542                  */
543                 {T_DIRECT, SIP_MEDIA_FIXED, "IFS", "FC2/SATA-R*",
544                  "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
545         },
546         {
547                 /*
548                  * Samsung YP-U3 mp3-player
549                  * PR: 125398
550                  */
551                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "Samsung", "YP-U3",
552                  "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
553         },
554         {
555                 {T_DIRECT, SIP_MEDIA_REMOVABLE, "Netac", "OnlyDisk*",
556                  "2000"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
557         }
558 };
559 
560 static  disk_strategy_t dastrategy;
561 static  dumper_t        dadump;
562 static  periph_init_t   dainit;
563 static  void            daasync(void *callback_arg, u_int32_t code,
564                                 struct cam_path *path, void *arg);
565 static  void            dasysctlinit(void *context, int pending);
566 static  int             dacmdsizesysctl(SYSCTL_HANDLER_ARGS);
567 static  periph_ctor_t   daregister;
568 static  periph_dtor_t   dacleanup;
569 static  periph_start_t  dastart;
570 static  periph_oninv_t  daoninvalidate;
571 static  void            dadone(struct cam_periph *periph,
572                                union ccb *done_ccb);
573 static  int             daerror(union ccb *ccb, u_int32_t cam_flags,
574                                 u_int32_t sense_flags);
575 static void             daprevent(struct cam_periph *periph, int action);
576 static int              dagetcapacity(struct cam_periph *periph);
577 static void             dasetgeom(struct cam_periph *periph, uint32_t block_len,
578                                   uint64_t maxsector);
579 static timeout_t        dasendorderedtag;
580 static void             dashutdown(void *arg, int howto);
581 
582 #ifndef DA_DEFAULT_TIMEOUT
583 #define DA_DEFAULT_TIMEOUT 60   /* Timeout in seconds */
584 #endif
585 
586 #ifndef DA_DEFAULT_RETRY
587 #define DA_DEFAULT_RETRY        4
588 #endif
589 
590 #ifndef DA_DEFAULT_SEND_ORDERED
591 #define DA_DEFAULT_SEND_ORDERED 1
592 #endif
593 
594 
595 static int da_retry_count = DA_DEFAULT_RETRY;
596 static int da_default_timeout = DA_DEFAULT_TIMEOUT;
597 static int da_send_ordered = DA_DEFAULT_SEND_ORDERED;
598 
599 SYSCTL_NODE(_kern_cam, OID_AUTO, da, CTLFLAG_RD, 0,
600             "CAM Direct Access Disk driver");
601 SYSCTL_INT(_kern_cam_da, OID_AUTO, retry_count, CTLFLAG_RW,
602            &da_retry_count, 0, "Normal I/O retry count");
603 TUNABLE_INT("kern.cam.da.retry_count", &da_retry_count);
604 SYSCTL_INT(_kern_cam_da, OID_AUTO, default_timeout, CTLFLAG_RW,
605            &da_default_timeout, 0, "Normal I/O timeout (in seconds)");
606 TUNABLE_INT("kern.cam.da.default_timeout", &da_default_timeout);
607 SYSCTL_INT(_kern_cam_da, OID_AUTO, da_send_ordered, CTLFLAG_RW,
608            &da_send_ordered, 0, "Send Ordered Tags");
609 TUNABLE_INT("kern.cam.da.da_send_ordered", &da_send_ordered);
610 
611 /*
612  * DA_ORDEREDTAG_INTERVAL determines how often, relative
613  * to the default timeout, we check to see whether an ordered
614  * tagged transaction is appropriate to prevent simple tag
615  * starvation.  Since we'd like to ensure that there is at least
616  * 1/2 of the timeout length left for a starved transaction to
617  * complete after we've sent an ordered tag, we must poll at least
618  * four times in every timeout period.  This takes care of the worst
619  * case where a starved transaction starts during an interval that
620  * meets the requirement "don't send an ordered tag" test so it takes
621  * us two intervals to determine that a tag must be sent.
622  */
623 #ifndef DA_ORDEREDTAG_INTERVAL
624 #define DA_ORDEREDTAG_INTERVAL 4
625 #endif
626 
627 static struct periph_driver dadriver =
628 {
629         dainit, "da",
630         TAILQ_HEAD_INITIALIZER(dadriver.units), /* generation */ 0
631 };
632 
633 PERIPHDRIVER_DECLARE(da, dadriver);
634 
635 MALLOC_DEFINE(M_SCSIDA, "scsi_da", "scsi_da buffers");
636 
637 static int
638 daopen(struct disk *dp)
639 {
640         struct cam_periph *periph;
641         struct da_softc *softc;
642         int unit;
643         int error;
644 
645         periph = (struct cam_periph *)dp->d_drv1;
646         if (periph == NULL) {
647                 return (ENXIO); 
648         }
649 
650         if (cam_periph_acquire(periph) != CAM_REQ_CMP) {
651                 return(ENXIO);
652         }
653 
654         cam_periph_lock(periph);
655         if ((error = cam_periph_hold(periph, PRIBIO|PCATCH)) != 0) {
656                 cam_periph_unlock(periph);
657                 cam_periph_release(periph);
658                 return (error);
659         }
660 
661         unit = periph->unit_number;
662         softc = (struct da_softc *)periph->softc;
663         softc->flags |= DA_FLAG_OPEN;
664 
665         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,
666             ("daopen: disk=%s%d (unit %d)\n", dp->d_name, dp->d_unit,
667              unit));
668 
669         if ((softc->flags & DA_FLAG_PACK_INVALID) != 0) {
670                 /* Invalidate our pack information. */
671                 softc->flags &= ~DA_FLAG_PACK_INVALID;
672         }
673 
674         error = dagetcapacity(periph);
675 
676         if (error == 0) {
677 
678                 softc->disk->d_sectorsize = softc->params.secsize;
679                 softc->disk->d_mediasize = softc->params.secsize * (off_t)softc->params.sectors;
680                 /* XXX: these are not actually "firmware" values, so they may be wrong */
681                 softc->disk->d_fwsectors = softc->params.secs_per_track;
682                 softc->disk->d_fwheads = softc->params.heads;
683                 softc->disk->d_devstat->block_size = softc->params.secsize;
684                 softc->disk->d_devstat->flags &= ~DEVSTAT_BS_UNAVAILABLE;
685 
686                 if ((softc->flags & DA_FLAG_PACK_REMOVABLE) != 0 &&
687                     (softc->quirks & DA_Q_NO_PREVENT) == 0)
688                         daprevent(periph, PR_PREVENT);
689         } else
690                 softc->flags &= ~DA_FLAG_OPEN;
691 
692         cam_periph_unhold(periph);
693         cam_periph_unlock(periph);
694 
695         if (error != 0) {
696                 cam_periph_release(periph);
697         }
698         return (error);
699 }
700 
701 static int
702 daclose(struct disk *dp)
703 {
704         struct  cam_periph *periph;
705         struct  da_softc *softc;
706         int error;
707 
708         periph = (struct cam_periph *)dp->d_drv1;
709         if (periph == NULL)
710                 return (ENXIO); 
711 
712         cam_periph_lock(periph);
713         if ((error = cam_periph_hold(periph, PRIBIO)) != 0) {
714                 cam_periph_unlock(periph);
715                 cam_periph_release(periph);
716                 return (error);
717         }
718 
719         softc = (struct da_softc *)periph->softc;
720 
721         if ((softc->quirks & DA_Q_NO_SYNC_CACHE) == 0) {
722                 union   ccb *ccb;
723 
724                 ccb = cam_periph_getccb(periph, /*priority*/1);
725 
726                 scsi_synchronize_cache(&ccb->csio,
727                                        /*retries*/1,
728                                        /*cbfcnp*/dadone,
729                                        MSG_SIMPLE_Q_TAG,
730                                        /*begin_lba*/0,/* Cover the whole disk */
731                                        /*lb_count*/0,
732                                        SSD_FULL_SIZE,
733                                        5 * 60 * 1000);
734 
735                 cam_periph_runccb(ccb, /*error_routine*/NULL, /*cam_flags*/0,
736                                   /*sense_flags*/SF_RETRY_UA,
737                                   softc->disk->d_devstat);
738 
739                 if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
740                         if ((ccb->ccb_h.status & CAM_STATUS_MASK) ==
741                              CAM_SCSI_STATUS_ERROR) {
742                                 int asc, ascq;
743                                 int sense_key, error_code;
744 
745                                 scsi_extract_sense(&ccb->csio.sense_data,
746                                                    &error_code,
747                                                    &sense_key, 
748                                                    &asc, &ascq);
749                                 if (sense_key != SSD_KEY_ILLEGAL_REQUEST)
750                                         scsi_sense_print(&ccb->csio);
751                         } else {
752                                 xpt_print(periph->path, "Synchronize cache "
753                                     "failed, status == 0x%x, scsi status == "
754                                     "0x%x\n", ccb->csio.ccb_h.status,
755                                     ccb->csio.scsi_status);
756                         }
757                 }
758 
759                 if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
760                         cam_release_devq(ccb->ccb_h.path,
761                                          /*relsim_flags*/0,
762                                          /*reduction*/0,
763                                          /*timeout*/0,
764                                          /*getcount_only*/0);
765 
766                 xpt_release_ccb(ccb);
767 
768         }
769 
770         if ((softc->flags & DA_FLAG_PACK_REMOVABLE) != 0) {
771                 if ((softc->quirks & DA_Q_NO_PREVENT) == 0)
772                         daprevent(periph, PR_ALLOW);
773                 /*
774                  * If we've got removeable media, mark the blocksize as
775                  * unavailable, since it could change when new media is
776                  * inserted.
777                  */
778                 softc->disk->d_devstat->flags |= DEVSTAT_BS_UNAVAILABLE;
779         }
780 
781         softc->flags &= ~DA_FLAG_OPEN;
782         cam_periph_unhold(periph);
783         cam_periph_unlock(periph);
784         cam_periph_release(periph);
785         return (0);     
786 }
787 
788 /*
789  * Actually translate the requested transfer into one the physical driver
790  * can understand.  The transfer is described by a buf and will include
791  * only one physical transfer.
792  */
793 static void
794 dastrategy(struct bio *bp)
795 {
796         struct cam_periph *periph;
797         struct da_softc *softc;
798         
799         periph = (struct cam_periph *)bp->bio_disk->d_drv1;
800         if (periph == NULL) {
801                 biofinish(bp, NULL, ENXIO);
802                 return;
803         }
804         softc = (struct da_softc *)periph->softc;
805 
806         cam_periph_lock(periph);
807 
808 #if 0
809         /*
810          * check it's not too big a transfer for our adapter
811          */
812         scsi_minphys(bp,&sd_switch);
813 #endif
814 
815         /*
816          * Mask interrupts so that the pack cannot be invalidated until
817          * after we are in the queue.  Otherwise, we might not properly
818          * clean up one of the buffers.
819          */
820         
821         /*
822          * If the device has been made invalid, error out
823          */
824         if ((softc->flags & DA_FLAG_PACK_INVALID)) {
825                 cam_periph_unlock(periph);
826                 biofinish(bp, NULL, ENXIO);
827                 return;
828         }
829         
830         /*
831          * Place it in the queue of disk activities for this disk
832          */
833         bioq_disksort(&softc->bio_queue, bp);
834 
835         /*
836          * Schedule ourselves for performing the work.
837          */
838         xpt_schedule(periph, /* XXX priority */1);
839         cam_periph_unlock(periph);
840 
841         return;
842 }
843 
844 static int
845 dadump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size_t length)
846 {
847         struct      cam_periph *periph;
848         struct      da_softc *softc;
849         u_int       secsize;
850         struct      ccb_scsiio csio;
851         struct      disk *dp;
852 
853         dp = arg;
854         periph = dp->d_drv1;
855         if (periph == NULL)
856                 return (ENXIO);
857         softc = (struct da_softc *)periph->softc;
858         cam_periph_lock(periph);
859         secsize = softc->params.secsize;
860         
861         if ((softc->flags & DA_FLAG_PACK_INVALID) != 0) {
862                 cam_periph_unlock(periph);
863                 return (ENXIO);
864         }
865 
866         if (length > 0) {
867                 periph->flags |= CAM_PERIPH_POLLED;
868                 xpt_setup_ccb(&csio.ccb_h, periph->path, /*priority*/1);
869                 csio.ccb_h.ccb_state = DA_CCB_DUMP;
870                 scsi_read_write(&csio,
871                                 /*retries*/1,
872                                 dadone,
873                                 MSG_ORDERED_Q_TAG,
874                                 /*read*/FALSE,
875                                 /*byte2*/0,
876                                 /*minimum_cmd_size*/ softc->minimum_cmd_size,
877                                 offset / secsize,
878                                 length / secsize,
879                                 /*data_ptr*/(u_int8_t *) virtual,
880                                 /*dxfer_len*/length,
881                                 /*sense_len*/SSD_FULL_SIZE,
882                                 DA_DEFAULT_TIMEOUT * 1000);             
883                 xpt_polled_action((union ccb *)&csio);
884 
885                 if ((csio.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
886                         printf("Aborting dump due to I/O error.\n");
887                         if ((csio.ccb_h.status & CAM_STATUS_MASK) ==
888                              CAM_SCSI_STATUS_ERROR)
889                                 scsi_sense_print(&csio);
890                         else
891                                 printf("status == 0x%x, scsi status == 0x%x\n",
892                                        csio.ccb_h.status, csio.scsi_status);
893                         periph->flags |= CAM_PERIPH_POLLED;
894                         return(EIO);
895                 }
896                 cam_periph_unlock(periph);
897                 return(0);
898         }
899                 
900         /*
901          * Sync the disk cache contents to the physical media.
902          */
903         if ((softc->quirks & DA_Q_NO_SYNC_CACHE) == 0) {
904 
905                 xpt_setup_ccb(&csio.ccb_h, periph->path, /*priority*/1);
906                 csio.ccb_h.ccb_state = DA_CCB_DUMP;
907                 scsi_synchronize_cache(&csio,
908                                        /*retries*/1,
909                                        /*cbfcnp*/dadone,
910                                        MSG_SIMPLE_Q_TAG,
911                                        /*begin_lba*/0,/* Cover the whole disk */
912                                        /*lb_count*/0,
913                                        SSD_FULL_SIZE,
914                                        5 * 60 * 1000);
915                 xpt_polled_action((union ccb *)&csio);
916 
917                 if ((csio.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
918                         if ((csio.ccb_h.status & CAM_STATUS_MASK) ==
919                              CAM_SCSI_STATUS_ERROR) {
920                                 int asc, ascq;
921                                 int sense_key, error_code;
922 
923                                 scsi_extract_sense(&csio.sense_data,
924                                                    &error_code,
925                                                    &sense_key, 
926                                                    &asc, &ascq);
927                                 if (sense_key != SSD_KEY_ILLEGAL_REQUEST)
928                                         scsi_sense_print(&csio);
929                         } else {
930                                 xpt_print(periph->path, "Synchronize cache "
931                                     "failed, status == 0x%x, scsi status == "
932                                     "0x%x\n", csio.ccb_h.status,
933                                     csio.scsi_status);
934                         }
935                 }
936         }
937         periph->flags &= ~CAM_PERIPH_POLLED;
938         cam_periph_unlock(periph);
939         return (0);
940 }
941 
942 static void
943 dainit(void)
944 {
945         cam_status status;
946 
947         /*
948          * Install a global async callback.  This callback will
949          * receive async callbacks like "new device found".
950          */
951         status = xpt_register_async(AC_FOUND_DEVICE, daasync, NULL, NULL);
952 
953         if (status != CAM_REQ_CMP) {
954                 printf("da: Failed to attach master async callback "
955                        "due to status 0x%x!\n", status);
956         } else if (da_send_ordered) {
957 
958                 /* Register our shutdown event handler */
959                 if ((EVENTHANDLER_REGISTER(shutdown_post_sync, dashutdown, 
960                                            NULL, SHUTDOWN_PRI_DEFAULT)) == NULL)
961                     printf("dainit: shutdown event registration failed!\n");
962         }
963 }
964 
965 static void
966 daoninvalidate(struct cam_periph *periph)
967 {
968         struct da_softc *softc;
969 
970         softc = (struct da_softc *)periph->softc;
971 
972         /*
973          * De-register any async callbacks.
974          */
975         xpt_register_async(0, daasync, periph, periph->path);
976 
977         softc->flags |= DA_FLAG_PACK_INVALID;
978 
979         /*
980          * Return all queued I/O with ENXIO.
981          * XXX Handle any transactions queued to the card
982          *     with XPT_ABORT_CCB.
983          */
984         bioq_flush(&softc->bio_queue, NULL, ENXIO);
985 
986         disk_gone(softc->disk);
987         xpt_print(periph->path, "lost device\n");
988 }
989 
990 static void
991 dacleanup(struct cam_periph *periph)
992 {
993         struct da_softc *softc;
994 
995         softc = (struct da_softc *)periph->softc;
996 
997         xpt_print(periph->path, "removing device entry\n");
998         /*
999          * If we can't free the sysctl tree, oh well...
1000          */
1001         if ((softc->flags & DA_FLAG_SCTX_INIT) != 0
1002             && sysctl_ctx_free(&softc->sysctl_ctx) != 0) {
1003                 xpt_print(periph->path, "can't remove sysctl context\n");
1004         }
1005 
1006         cam_periph_unlock(periph);
1007         disk_destroy(softc->disk);
1008         callout_drain(&softc->sendordered_c);
1009         cam_periph_lock(periph);
1010         free(softc, M_DEVBUF);
1011 }
1012 
1013 static void
1014 daasync(void *callback_arg, u_int32_t code,
1015         struct cam_path *path, void *arg)
1016 {
1017         struct cam_periph *periph;
1018 
1019         periph = (struct cam_periph *)callback_arg;
1020         switch (code) {
1021         case AC_FOUND_DEVICE:
1022         {
1023                 struct ccb_getdev *cgd;
1024                 struct cam_sim *sim;