scsi_ioctl.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. /* $OpenBSD: scsi_ioctl.c,v 1.51 2015/06/07 19:13:27 krw Exp $ */
  2. /* $NetBSD: scsi_ioctl.c,v 1.23 1996/10/12 23:23:17 christos Exp $ */
  3. /*
  4. * Copyright (c) 1994 Charles Hannum. All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. * 3. All advertising materials mentioning features or use of this software
  15. * must display the following acknowledgement:
  16. * This product includes software developed by Charles Hannum.
  17. * 4. The name of the author may not be used to endorse or promote products
  18. * derived from this software without specific prior written permission.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  21. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  22. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  23. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  24. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  25. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  26. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  27. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  28. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  29. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. */
  31. /*
  32. * Contributed by HD Associates (hd@world.std.com).
  33. * Copyright (c) 1992, 1993 HD Associates
  34. *
  35. * Berkeley style copyright.
  36. */
  37. #include <sys/types.h>
  38. #include <sys/errno.h>
  39. #include <sys/param.h>
  40. #include <sys/systm.h>
  41. #include <sys/file.h>
  42. #include <sys/pool.h>
  43. #include <sys/device.h>
  44. #include <sys/fcntl.h>
  45. #include <scsi/scsi_all.h>
  46. #include <scsi/scsiconf.h>
  47. #include <sys/scsiio.h>
  48. #include <sys/ataio.h>
  49. int scsi_ioc_cmd(struct scsi_link *, scsireq_t *);
  50. int scsi_ioc_ata_cmd(struct scsi_link *, atareq_t *);
  51. const unsigned char scsi_readsafe_cmd[256] = {
  52. [0x00] = 1, /* TEST UNIT READY */
  53. [0x03] = 1, /* REQUEST SENSE */
  54. [0x08] = 1, /* READ(6) */
  55. [0x12] = 1, /* INQUIRY */
  56. [0x1a] = 1, /* MODE SENSE */
  57. [0x1b] = 1, /* START STOP */
  58. [0x23] = 1, /* READ FORMAT CAPACITIES */
  59. [0x25] = 1, /* READ CDVD CAPACITY */
  60. [0x28] = 1, /* READ(10) */
  61. [0x2b] = 1, /* SEEK */
  62. [0x2f] = 1, /* VERIFY(10) */
  63. [0x3c] = 1, /* READ BUFFER */
  64. [0x3e] = 1, /* READ LONG */
  65. [0x42] = 1, /* READ SUBCHANNEL */
  66. [0x43] = 1, /* READ TOC PMA ATIP */
  67. [0x44] = 1, /* READ HEADER */
  68. [0x45] = 1, /* PLAY AUDIO(10) */
  69. [0x46] = 1, /* GET CONFIGURATION */
  70. [0x47] = 1, /* PLAY AUDIO MSF */
  71. [0x48] = 1, /* PLAY AUDIO TI */
  72. [0x4a] = 1, /* GET EVENT STATUS NOTIFICATION */
  73. [0x4b] = 1, /* PAUSE RESUME */
  74. [0x4e] = 1, /* STOP PLAY SCAN */
  75. [0x51] = 1, /* READ DISC INFO */
  76. [0x52] = 1, /* READ TRACK RZONE INFO */
  77. [0x5a] = 1, /* MODE SENSE(10) */
  78. [0x88] = 1, /* READ(16) */
  79. [0x8f] = 1, /* VERIFY(16) */
  80. [0xa4] = 1, /* REPORT KEY */
  81. [0xa5] = 1, /* PLAY AUDIO(12) */
  82. [0xa8] = 1, /* READ(12) */
  83. [0xac] = 1, /* GET PERFORMANCE */
  84. [0xad] = 1, /* READ DVD STRUCTURE */
  85. [0xb9] = 1, /* READ CD MSF */
  86. [0xba] = 1, /* SCAN */
  87. [0xbc] = 1, /* PLAY CD */
  88. [0xbd] = 1, /* MECHANISM STATUS */
  89. [0xbe] = 1 /* READ CD */
  90. };
  91. int
  92. scsi_ioc_cmd(struct scsi_link *link, scsireq_t *screq)
  93. {
  94. struct scsi_xfer *xs;
  95. int err = 0;
  96. if (screq->cmdlen > sizeof(struct scsi_generic))
  97. return (EFAULT);
  98. if (screq->datalen > MAXPHYS)
  99. return (EINVAL);
  100. xs = scsi_xs_get(link, 0);
  101. if (xs == NULL)
  102. return (ENOMEM);
  103. memcpy(xs->cmd, screq->cmd, screq->cmdlen);
  104. xs->cmdlen = screq->cmdlen;
  105. if (screq->datalen > 0) {
  106. xs->data = dma_alloc(screq->datalen, PR_WAITOK | PR_ZERO);
  107. if (xs->data == NULL) {
  108. err = ENOMEM;
  109. goto err;
  110. }
  111. xs->datalen = screq->datalen;
  112. }
  113. if (screq->flags & SCCMD_READ)
  114. xs->flags |= SCSI_DATA_IN;
  115. if (screq->flags & SCCMD_WRITE) {
  116. if (screq->datalen > 0) {
  117. err = copyin(screq->databuf, xs->data, screq->datalen);
  118. if (err != 0)
  119. goto err;
  120. }
  121. xs->flags |= SCSI_DATA_OUT;
  122. }
  123. xs->flags |= SCSI_SILENT; /* User is responsible for errors. */
  124. xs->timeout = screq->timeout;
  125. xs->retries = 0; /* user must do the retries *//* ignored */
  126. scsi_xs_sync(xs);
  127. screq->retsts = 0;
  128. screq->status = xs->status;
  129. switch (xs->error) {
  130. case XS_NOERROR:
  131. /* probably rubbish */
  132. screq->datalen_used = xs->datalen - xs->resid;
  133. screq->retsts = SCCMD_OK;
  134. break;
  135. case XS_SENSE:
  136. #ifdef SCSIDEBUG
  137. scsi_sense_print_debug(xs);
  138. #endif
  139. screq->senselen_used = min(sizeof(xs->sense),
  140. sizeof(screq->sense));
  141. memcpy(screq->sense, &xs->sense, screq->senselen_used);
  142. screq->retsts = SCCMD_SENSE;
  143. break;
  144. case XS_SHORTSENSE:
  145. #ifdef SCSIDEBUG
  146. scsi_sense_print_debug(xs);
  147. #endif
  148. printf("XS_SHORTSENSE\n");
  149. screq->senselen_used = min(sizeof(xs->sense),
  150. sizeof(screq->sense));
  151. memcpy(screq->sense, &xs->sense, screq->senselen_used);
  152. screq->retsts = SCCMD_UNKNOWN;
  153. break;
  154. case XS_DRIVER_STUFFUP:
  155. screq->retsts = SCCMD_UNKNOWN;
  156. break;
  157. case XS_TIMEOUT:
  158. screq->retsts = SCCMD_TIMEOUT;
  159. break;
  160. case XS_BUSY:
  161. screq->retsts = SCCMD_BUSY;
  162. break;
  163. default:
  164. screq->retsts = SCCMD_UNKNOWN;
  165. break;
  166. }
  167. if (screq->datalen > 0 && screq->flags & SCCMD_READ) {
  168. err = copyout(xs->data, screq->databuf, screq->datalen);
  169. if (err != 0)
  170. goto err;
  171. }
  172. err:
  173. if (xs->data)
  174. dma_free(xs->data, screq->datalen);
  175. scsi_xs_put(xs);
  176. return (err);
  177. }
  178. int
  179. scsi_ioc_ata_cmd(struct scsi_link *link, atareq_t *atareq)
  180. {
  181. struct scsi_xfer *xs;
  182. struct scsi_ata_passthru_12 *cdb;
  183. int err = 0;
  184. if (atareq->datalen > MAXPHYS)
  185. return (EINVAL);
  186. xs = scsi_xs_get(link, 0);
  187. if (xs == NULL)
  188. return (ENOMEM);
  189. cdb = (struct scsi_ata_passthru_12 *)xs->cmd;
  190. cdb->opcode = ATA_PASSTHRU_12;
  191. if (atareq->datalen > 0) {
  192. if (atareq->flags & ATACMD_READ) {
  193. cdb->count_proto = ATA_PASSTHRU_PROTO_PIO_DATAIN;
  194. cdb->flags = ATA_PASSTHRU_T_DIR_READ;
  195. } else {
  196. cdb->count_proto = ATA_PASSTHRU_PROTO_PIO_DATAOUT;
  197. cdb->flags = ATA_PASSTHRU_T_DIR_WRITE;
  198. }
  199. cdb->flags |= ATA_PASSTHRU_T_LEN_SECTOR_COUNT;
  200. } else {
  201. cdb->count_proto = ATA_PASSTHRU_PROTO_NON_DATA;
  202. cdb->flags = ATA_PASSTHRU_T_LEN_NONE;
  203. }
  204. cdb->features = atareq->features;
  205. cdb->sector_count = atareq->sec_count;
  206. cdb->lba_low = atareq->sec_num;
  207. cdb->lba_mid = atareq->cylinder;
  208. cdb->lba_high = atareq->cylinder >> 8;
  209. cdb->device = atareq->head & 0x0f;
  210. cdb->command = atareq->command;
  211. xs->cmdlen = sizeof(*cdb);
  212. if (atareq->datalen > 0) {
  213. xs->data = dma_alloc(atareq->datalen, PR_WAITOK | PR_ZERO);
  214. if (xs->data == NULL) {
  215. err = ENOMEM;
  216. goto err;
  217. }
  218. xs->datalen = atareq->datalen;
  219. }
  220. if (atareq->flags & ATACMD_READ)
  221. xs->flags |= SCSI_DATA_IN;
  222. if (atareq->flags & ATACMD_WRITE) {
  223. if (atareq->datalen > 0) {
  224. err = copyin(atareq->databuf, xs->data,
  225. atareq->datalen);
  226. if (err != 0)
  227. goto err;
  228. }
  229. xs->flags |= SCSI_DATA_OUT;
  230. }
  231. xs->flags |= SCSI_SILENT; /* User is responsible for errors. */
  232. xs->retries = 0; /* user must do the retries *//* ignored */
  233. scsi_xs_sync(xs);
  234. atareq->retsts = ATACMD_ERROR;
  235. switch (xs->error) {
  236. case XS_SENSE:
  237. case XS_SHORTSENSE:
  238. #ifdef SCSIDEBUG
  239. scsi_sense_print_debug(xs);
  240. #endif
  241. /* XXX this is not right */
  242. case XS_NOERROR:
  243. atareq->retsts = ATACMD_OK;
  244. break;
  245. default:
  246. atareq->retsts = ATACMD_ERROR;
  247. break;
  248. }
  249. if (atareq->datalen > 0 && atareq->flags & ATACMD_READ) {
  250. err = copyout(xs->data, atareq->databuf, atareq->datalen);
  251. if (err != 0)
  252. goto err;
  253. }
  254. err:
  255. if (xs->data)
  256. dma_free(xs->data, atareq->datalen);
  257. scsi_xs_put(xs);
  258. return (err);
  259. }
  260. /*
  261. * Something (e.g. another driver) has called us
  262. * with an sc_link for a target/lun/adapter, and a scsi
  263. * specific ioctl to perform, better try.
  264. */
  265. int
  266. scsi_do_ioctl(struct scsi_link *sc_link, u_long cmd, caddr_t addr, int flag)
  267. {
  268. SC_DEBUG(sc_link, SDEV_DB2, ("scsi_do_ioctl(0x%lx)\n", cmd));
  269. switch(cmd) {
  270. case SCIOCIDENTIFY: {
  271. struct scsi_addr *sca = (struct scsi_addr *)addr;
  272. if ((sc_link->flags & (SDEV_ATAPI | SDEV_UMASS)) == 0)
  273. /* A 'real' SCSI target. */
  274. sca->type = TYPE_SCSI;
  275. else
  276. /* An 'emulated' SCSI target. */
  277. sca->type = TYPE_ATAPI;
  278. sca->scbus = sc_link->bus->sc_dev.dv_unit;
  279. sca->target = sc_link->target;
  280. sca->lun = sc_link->lun;
  281. return (0);
  282. }
  283. case SCIOCCOMMAND:
  284. if (scsi_readsafe_cmd[((scsireq_t *)addr)->cmd[0]])
  285. break;
  286. /* FALLTHROUGH */
  287. case ATAIOCCOMMAND:
  288. case SCIOCDEBUG:
  289. if ((flag & FWRITE) == 0)
  290. return (EPERM);
  291. break;
  292. default:
  293. if (sc_link->adapter->ioctl)
  294. return ((sc_link->adapter->ioctl)(sc_link, cmd, addr,
  295. flag));
  296. else
  297. return (ENOTTY);
  298. }
  299. switch(cmd) {
  300. case SCIOCCOMMAND:
  301. return (scsi_ioc_cmd(sc_link, (scsireq_t *)addr));
  302. case ATAIOCCOMMAND:
  303. return (scsi_ioc_ata_cmd(sc_link, (atareq_t *)addr));
  304. case SCIOCDEBUG: {
  305. int level = *((int *)addr);
  306. SC_DEBUG(sc_link, SDEV_DB3, ("debug set to %d\n", level));
  307. sc_link->flags &= ~SDEV_DBX; /* clear debug bits */
  308. if (level & 1)
  309. sc_link->flags |= SDEV_DB1;
  310. if (level & 2)
  311. sc_link->flags |= SDEV_DB2;
  312. if (level & 4)
  313. sc_link->flags |= SDEV_DB3;
  314. if (level & 8)
  315. sc_link->flags |= SDEV_DB4;
  316. return (0);
  317. }
  318. default:
  319. #ifdef DIAGNOSTIC
  320. panic("scsi_do_ioctl: impossible cmd (%#lx)", cmd);
  321. #endif
  322. return (0);
  323. }
  324. }