ch.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794
  1. /* $OpenBSD: ch.c,v 1.50 2015/03/14 03:38:52 jsg Exp $ */
  2. /* $NetBSD: ch.c,v 1.26 1997/02/21 22:06:52 thorpej Exp $ */
  3. /*
  4. * Copyright (c) 1996, 1997 Jason R. Thorpe <thorpej@and.com>
  5. * All rights reserved.
  6. *
  7. * Partially based on an autochanger driver written by Stefan Grefen
  8. * and on an autochanger driver written by the Systems Programming Group
  9. * at the University of Utah Computer Science Department.
  10. *
  11. * Redistribution and use in source and binary forms, with or without
  12. * modification, are permitted provided that the following conditions
  13. * are met:
  14. * 1. Redistributions of source code must retain the above copyright
  15. * notice, this list of conditions and the following disclaimer.
  16. * 2. Redistributions in binary form must reproduce the above copyright
  17. * notice, this list of conditions and the following disclaimer in the
  18. * documentation and/or other materials provided with the distribution.
  19. * 3. All advertising materials mentioning features or use of this software
  20. * must display the following acknowledgements:
  21. * This product includes software developed by Jason R. Thorpe
  22. * for And Communications, http://www.and.com/
  23. * 4. The name of the author may not be used to endorse or promote products
  24. * derived from this software without specific prior written permission.
  25. *
  26. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  27. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  28. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  29. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  30. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  31. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  32. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  33. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  34. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  35. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  36. * SUCH DAMAGE.
  37. */
  38. #include <sys/param.h>
  39. #include <sys/systm.h>
  40. #include <sys/errno.h>
  41. #include <sys/ioctl.h>
  42. #include <sys/chio.h>
  43. #include <sys/device.h>
  44. #include <sys/malloc.h>
  45. #include <sys/pool.h>
  46. #include <sys/conf.h>
  47. #include <sys/fcntl.h>
  48. #include <scsi/scsi_all.h>
  49. #include <scsi/scsi_changer.h>
  50. #include <scsi/scsiconf.h>
  51. #define CHRETRIES 2
  52. #define CHUNIT(x) (minor((x)))
  53. struct ch_softc {
  54. struct device sc_dev; /* generic device info */
  55. struct scsi_link *sc_link; /* link in the SCSI bus */
  56. int sc_picker; /* current picker */
  57. /*
  58. * The following information is obtained from the
  59. * element address assignment page.
  60. */
  61. int sc_firsts[4]; /* firsts, indexed by CHET_* */
  62. int sc_counts[4]; /* counts, indexed by CHET_* */
  63. /*
  64. * The following mask defines the legal combinations
  65. * of elements for the MOVE MEDIUM command.
  66. */
  67. u_int8_t sc_movemask[4];
  68. /*
  69. * As above, but for EXCHANGE MEDIUM.
  70. */
  71. u_int8_t sc_exchangemask[4];
  72. int flags; /* misc. info */
  73. /*
  74. * Quirks; see below.
  75. */
  76. int sc_settledelay; /* delay for settle */
  77. };
  78. /* sc_flags */
  79. #define CHF_ROTATE 0x01 /* picker can rotate */
  80. /* Autoconfiguration glue */
  81. int chmatch(struct device *, void *, void *);
  82. void chattach(struct device *, struct device *, void *);
  83. struct cfattach ch_ca = {
  84. sizeof(struct ch_softc), chmatch, chattach
  85. };
  86. struct cfdriver ch_cd = {
  87. NULL, "ch", DV_DULL
  88. };
  89. const struct scsi_inquiry_pattern ch_patterns[] = {
  90. {T_CHANGER, T_REMOV,
  91. "", "", ""},
  92. };
  93. int ch_move(struct ch_softc *, struct changer_move *);
  94. int ch_exchange(struct ch_softc *, struct changer_exchange *);
  95. int ch_position(struct ch_softc *, struct changer_position *);
  96. int ch_usergetelemstatus(struct ch_softc *,
  97. struct changer_element_status_request *);
  98. int ch_getelemstatus(struct ch_softc *, int, int, caddr_t, size_t, int);
  99. int ch_get_params(struct ch_softc *, int);
  100. int ch_interpret_sense(struct scsi_xfer *xs);
  101. void ch_get_quirks(struct ch_softc *, struct scsi_inquiry_data *);
  102. /*
  103. * SCSI changer quirks.
  104. */
  105. struct chquirk {
  106. struct scsi_inquiry_pattern cq_match; /* device id pattern */
  107. int cq_settledelay; /* settle delay, in seconds */
  108. };
  109. struct chquirk chquirks[] = {
  110. {{T_CHANGER, T_REMOV,
  111. "SPECTRA", "9000", "0200"},
  112. 75},
  113. };
  114. int
  115. chmatch(struct device *parent, void *match, void *aux)
  116. {
  117. struct scsi_attach_args *sa = aux;
  118. int priority;
  119. (void)scsi_inqmatch(sa->sa_inqbuf,
  120. ch_patterns, nitems(ch_patterns),
  121. sizeof(ch_patterns[0]), &priority);
  122. return (priority);
  123. }
  124. void
  125. chattach(struct device *parent, struct device *self, void *aux)
  126. {
  127. struct ch_softc *sc = (struct ch_softc *)self;
  128. struct scsi_attach_args *sa = aux;
  129. struct scsi_link *link = sa->sa_sc_link;
  130. /* Glue into the SCSI bus */
  131. sc->sc_link = link;
  132. link->interpret_sense = ch_interpret_sense;
  133. link->device_softc = sc;
  134. link->openings = 1;
  135. printf("\n");
  136. /*
  137. * Store our our device's quirks.
  138. */
  139. ch_get_quirks(sc, sa->sa_inqbuf);
  140. }
  141. int
  142. chopen(dev_t dev, int flags, int fmt, struct proc *p)
  143. {
  144. struct ch_softc *sc;
  145. int oldcounts[4];
  146. int i, unit, error = 0;
  147. unit = CHUNIT(dev);
  148. if ((unit >= ch_cd.cd_ndevs) ||
  149. ((sc = ch_cd.cd_devs[unit]) == NULL))
  150. return (ENXIO);
  151. /*
  152. * Only allow one open at a time.
  153. */
  154. if (sc->sc_link->flags & SDEV_OPEN)
  155. return (EBUSY);
  156. sc->sc_link->flags |= SDEV_OPEN;
  157. /*
  158. * Absorb any unit attention errors. We must notice
  159. * "Not ready" errors as a changer will report "In the
  160. * process of getting ready" any time it must rescan
  161. * itself to determine the state of the changer.
  162. */
  163. error = scsi_test_unit_ready(sc->sc_link, TEST_READY_RETRIES,
  164. SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_IGNORE_MEDIA_CHANGE);
  165. if (error)
  166. goto bad;
  167. /*
  168. * Get information about the device. Save old information
  169. * so we can decide whether to be verbose about new parameters.
  170. */
  171. for (i = 0; i < 4; i++) {
  172. oldcounts[i] = sc->sc_counts[i];
  173. }
  174. error = ch_get_params(sc, scsi_autoconf);
  175. if (error)
  176. goto bad;
  177. for (i = 0; i < 4; i++) {
  178. if (oldcounts[i] != sc->sc_counts[i]) {
  179. break;
  180. }
  181. }
  182. if (i < 4) {
  183. #ifdef CHANGER_DEBUG
  184. #define PLURAL(c) (c) == 1 ? "" : "s"
  185. printf("%s: %d slot%s, %d drive%s, %d picker%s, %d portal%s\n",
  186. sc->sc_dev.dv_xname,
  187. sc->sc_counts[CHET_ST], PLURAL(sc->sc_counts[CHET_ST]),
  188. sc->sc_counts[CHET_DT], PLURAL(sc->sc_counts[CHET_DT]),
  189. sc->sc_counts[CHET_MT], PLURAL(sc->sc_counts[CHET_MT]),
  190. sc->sc_counts[CHET_IE], PLURAL(sc->sc_counts[CHET_IE]));
  191. #undef PLURAL
  192. printf("%s: move mask: 0x%x 0x%x 0x%x 0x%x\n",
  193. sc->sc_dev.dv_xname,
  194. sc->sc_movemask[CHET_MT], sc->sc_movemask[CHET_ST],
  195. sc->sc_movemask[CHET_IE], sc->sc_movemask[CHET_DT]);
  196. printf("%s: exchange mask: 0x%x 0x%x 0x%x 0x%x\n",
  197. sc->sc_dev.dv_xname,
  198. sc->sc_exchangemask[CHET_MT], sc->sc_exchangemask[CHET_ST],
  199. sc->sc_exchangemask[CHET_IE], sc->sc_exchangemask[CHET_DT]);
  200. #endif /* CHANGER_DEBUG */
  201. }
  202. /* Default the current picker. */
  203. sc->sc_picker = sc->sc_firsts[CHET_MT];
  204. return (0);
  205. bad:
  206. sc->sc_link->flags &= ~SDEV_OPEN;
  207. return (error);
  208. }
  209. int
  210. chclose(dev_t dev, int flags, int fmt, struct proc *p)
  211. {
  212. struct ch_softc *sc = ch_cd.cd_devs[CHUNIT(dev)];
  213. sc->sc_link->flags &= ~SDEV_OPEN;
  214. return (0);
  215. }
  216. int
  217. chioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
  218. {
  219. struct ch_softc *sc = ch_cd.cd_devs[CHUNIT(dev)];
  220. int error = 0;
  221. /*
  222. * If this command can change the device's state, we must
  223. * have the device open for writing.
  224. */
  225. switch (cmd) {
  226. case CHIOGPICKER:
  227. case CHIOGPARAMS:
  228. case CHIOGSTATUS:
  229. break;
  230. default:
  231. if ((flags & FWRITE) == 0)
  232. return (EBADF);
  233. }
  234. switch (cmd) {
  235. case CHIOMOVE:
  236. error = ch_move(sc, (struct changer_move *)data);
  237. break;
  238. case CHIOEXCHANGE:
  239. error = ch_exchange(sc, (struct changer_exchange *)data);
  240. break;
  241. case CHIOPOSITION:
  242. error = ch_position(sc, (struct changer_position *)data);
  243. break;
  244. case CHIOGPICKER:
  245. *(int *)data = sc->sc_picker - sc->sc_firsts[CHET_MT];
  246. break;
  247. case CHIOSPICKER: {
  248. int new_picker = *(int *)data;
  249. if (new_picker > (sc->sc_counts[CHET_MT] - 1))
  250. return (EINVAL);
  251. sc->sc_picker = sc->sc_firsts[CHET_MT] + new_picker;
  252. break; }
  253. case CHIOGPARAMS: {
  254. struct changer_params *cp = (struct changer_params *)data;
  255. cp->cp_curpicker = sc->sc_picker - sc->sc_firsts[CHET_MT];
  256. cp->cp_npickers = sc->sc_counts[CHET_MT];
  257. cp->cp_nslots = sc->sc_counts[CHET_ST];
  258. cp->cp_nportals = sc->sc_counts[CHET_IE];
  259. cp->cp_ndrives = sc->sc_counts[CHET_DT];
  260. break; }
  261. case CHIOGSTATUS: {
  262. struct changer_element_status_request *cesr =
  263. (struct changer_element_status_request *)data;
  264. error = ch_usergetelemstatus(sc, cesr);
  265. break; }
  266. /* Implement prevent/allow? */
  267. default:
  268. error = scsi_do_ioctl(sc->sc_link, cmd, data, flags);
  269. break;
  270. }
  271. return (error);
  272. }
  273. int
  274. ch_move(struct ch_softc *sc, struct changer_move *cm)
  275. {
  276. struct scsi_move_medium *cmd;
  277. struct scsi_xfer *xs;
  278. int error;
  279. u_int16_t fromelem, toelem;
  280. /*
  281. * Check arguments.
  282. */
  283. if ((cm->cm_fromtype > CHET_DT) || (cm->cm_totype > CHET_DT))
  284. return (EINVAL);
  285. if ((cm->cm_fromunit > (sc->sc_counts[cm->cm_fromtype] - 1)) ||
  286. (cm->cm_tounit > (sc->sc_counts[cm->cm_totype] - 1)))
  287. return (ENODEV);
  288. /*
  289. * Check the request against the changer's capabilities.
  290. */
  291. if ((sc->sc_movemask[cm->cm_fromtype] & (1 << cm->cm_totype)) == 0)
  292. return (EINVAL);
  293. /*
  294. * Calculate the source and destination elements.
  295. */
  296. fromelem = sc->sc_firsts[cm->cm_fromtype] + cm->cm_fromunit;
  297. toelem = sc->sc_firsts[cm->cm_totype] + cm->cm_tounit;
  298. /*
  299. * Build the SCSI command.
  300. */
  301. xs = scsi_xs_get(sc->sc_link, 0);
  302. if (xs == NULL)
  303. return (ENOMEM);
  304. xs->cmdlen = sizeof(*cmd);
  305. xs->retries = CHRETRIES;
  306. xs->timeout = 100000;
  307. cmd = (struct scsi_move_medium *)xs->cmd;
  308. cmd->opcode = MOVE_MEDIUM;
  309. _lto2b(sc->sc_picker, cmd->tea);
  310. _lto2b(fromelem, cmd->src);
  311. _lto2b(toelem, cmd->dst);
  312. if (cm->cm_flags & CM_INVERT)
  313. cmd->flags |= MOVE_MEDIUM_INVERT;
  314. error = scsi_xs_sync(xs);
  315. scsi_xs_put(xs);
  316. return (error);
  317. }
  318. int
  319. ch_exchange(struct ch_softc *sc, struct changer_exchange *ce)
  320. {
  321. struct scsi_exchange_medium *cmd;
  322. struct scsi_xfer *xs;
  323. int error;
  324. u_int16_t src, dst1, dst2;
  325. /*
  326. * Check arguments.
  327. */
  328. if ((ce->ce_srctype > CHET_DT) || (ce->ce_fdsttype > CHET_DT) ||
  329. (ce->ce_sdsttype > CHET_DT))
  330. return (EINVAL);
  331. if ((ce->ce_srcunit > (sc->sc_counts[ce->ce_srctype] - 1)) ||
  332. (ce->ce_fdstunit > (sc->sc_counts[ce->ce_fdsttype] - 1)) ||
  333. (ce->ce_sdstunit > (sc->sc_counts[ce->ce_sdsttype] - 1)))
  334. return (ENODEV);
  335. /*
  336. * Check the request against the changer's capabilities.
  337. */
  338. if (((sc->sc_exchangemask[ce->ce_srctype] &
  339. (1 << ce->ce_fdsttype)) == 0) ||
  340. ((sc->sc_exchangemask[ce->ce_fdsttype] &
  341. (1 << ce->ce_sdsttype)) == 0))
  342. return (EINVAL);
  343. /*
  344. * Calculate the source and destination elements.
  345. */
  346. src = sc->sc_firsts[ce->ce_srctype] + ce->ce_srcunit;
  347. dst1 = sc->sc_firsts[ce->ce_fdsttype] + ce->ce_fdstunit;
  348. dst2 = sc->sc_firsts[ce->ce_sdsttype] + ce->ce_sdstunit;
  349. /*
  350. * Build the SCSI command.
  351. */
  352. xs = scsi_xs_get(sc->sc_link, 0);
  353. if (xs == NULL)
  354. return (ENOMEM);
  355. xs->cmdlen = sizeof(*cmd);
  356. xs->retries = CHRETRIES;
  357. xs->timeout = 100000;
  358. cmd = (struct scsi_exchange_medium *)xs->cmd;
  359. cmd->opcode = EXCHANGE_MEDIUM;
  360. _lto2b(sc->sc_picker, cmd->tea);
  361. _lto2b(src, cmd->src);
  362. _lto2b(dst1, cmd->fdst);
  363. _lto2b(dst2, cmd->sdst);
  364. if (ce->ce_flags & CE_INVERT1)
  365. cmd->flags |= EXCHANGE_MEDIUM_INV1;
  366. if (ce->ce_flags & CE_INVERT2)
  367. cmd->flags |= EXCHANGE_MEDIUM_INV2;
  368. error = scsi_xs_sync(xs);
  369. scsi_xs_put(xs);
  370. return (error);
  371. }
  372. int
  373. ch_position(struct ch_softc *sc, struct changer_position *cp)
  374. {
  375. struct scsi_position_to_element *cmd;
  376. struct scsi_xfer *xs;
  377. int error;
  378. u_int16_t dst;
  379. /*
  380. * Check arguments.
  381. */
  382. if (cp->cp_type > CHET_DT)
  383. return (EINVAL);
  384. if (cp->cp_unit > (sc->sc_counts[cp->cp_type] - 1))
  385. return (ENODEV);
  386. /*
  387. * Calculate the destination element.
  388. */
  389. dst = sc->sc_firsts[cp->cp_type] + cp->cp_unit;
  390. /*
  391. * Build the SCSI command.
  392. */
  393. xs = scsi_xs_get(sc->sc_link, 0);
  394. if (xs == NULL)
  395. return (ENOMEM);
  396. xs->cmdlen = sizeof(*cmd);
  397. xs->retries = CHRETRIES;
  398. xs->timeout = 100000;
  399. cmd = (struct scsi_position_to_element *)xs->cmd;
  400. cmd->opcode = POSITION_TO_ELEMENT;
  401. _lto2b(sc->sc_picker, cmd->tea);
  402. _lto2b(dst, cmd->dst);
  403. if (cp->cp_flags & CP_INVERT)
  404. cmd->flags |= POSITION_TO_ELEMENT_INVERT;
  405. error = scsi_xs_sync(xs);
  406. scsi_xs_put(xs);
  407. return (error);
  408. }
  409. /*
  410. * Copy a volume tag to a volume_tag struct, converting SCSI byte order
  411. * to host native byte order in the volume serial number. The volume
  412. * label as returned by the changer is transferred to user mode as
  413. * nul-terminated string. Volume labels are truncated at the first
  414. * space, as suggested by SCSI-2.
  415. */
  416. static void
  417. copy_voltag(struct changer_voltag *uvoltag, struct volume_tag *voltag)
  418. {
  419. int i;
  420. for (i=0; i<CH_VOLTAG_MAXLEN; i++) {
  421. char c = voltag->vif[i];
  422. if (c && c != ' ')
  423. uvoltag->cv_volid[i] = c;
  424. else
  425. break;
  426. }
  427. uvoltag->cv_volid[i] = '\0';
  428. uvoltag->cv_serial = _2btol(voltag->vsn);
  429. }
  430. /*
  431. * Copy an an element status descriptor to a user-mode
  432. * changer_element_status structure.
  433. */
  434. static void
  435. copy_element_status(int flags, struct read_element_status_descriptor *desc,
  436. struct changer_element_status *ces)
  437. {
  438. ces->ces_flags = desc->flags1;
  439. if (flags & READ_ELEMENT_STATUS_PVOLTAG)
  440. copy_voltag(&ces->ces_pvoltag, &desc->pvoltag);
  441. if (flags & READ_ELEMENT_STATUS_AVOLTAG)
  442. copy_voltag(&ces->ces_avoltag, &desc->avoltag);
  443. }
  444. /*
  445. * Perform a READ ELEMENT STATUS on behalf of the user, and return to
  446. * the user only the data the user is interested in (i.e. an array of
  447. * changer_element_status structures)
  448. */
  449. int
  450. ch_usergetelemstatus(struct ch_softc *sc,
  451. struct changer_element_status_request *cesr)
  452. {
  453. struct changer_element_status *user_data = NULL;
  454. struct read_element_status_header *st_hdr;
  455. struct read_element_status_page_header *pg_hdr;
  456. caddr_t desc;
  457. caddr_t data = NULL;
  458. size_t size, desclen, udsize;
  459. int chet = cesr->cesr_type;
  460. int avail, i, error = 0;
  461. int want_voltags = (cesr->cesr_flags & CESR_VOLTAGS) ? 1 : 0;
  462. /*
  463. * If there are no elements of the requested type in the changer,
  464. * the request is invalid.
  465. */
  466. if (sc->sc_counts[chet] == 0)
  467. return (EINVAL);
  468. /*
  469. * Request one descriptor for the given element type. This
  470. * is used to determine the size of the descriptor so that
  471. * we can allocate enough storage for all of them. We assume
  472. * that the first one can fit into 1k.
  473. */
  474. size = 1024;
  475. data = dma_alloc(size, PR_WAITOK);
  476. error = ch_getelemstatus(sc, sc->sc_firsts[chet], 1, data, size,
  477. want_voltags);
  478. if (error)
  479. goto done;
  480. st_hdr = (struct read_element_status_header *)data;
  481. pg_hdr = (struct read_element_status_page_header *) (st_hdr + 1);
  482. desclen = _2btol(pg_hdr->edl);
  483. dma_free(data, size);
  484. /*
  485. * Reallocate storage for descriptors and get them from the
  486. * device.
  487. */
  488. size = sizeof(struct read_element_status_header) +
  489. sizeof(struct read_element_status_page_header) +
  490. (desclen * sc->sc_counts[chet]);
  491. data = dma_alloc(size, PR_WAITOK);
  492. error = ch_getelemstatus(sc, sc->sc_firsts[chet],
  493. sc->sc_counts[chet], data, size, want_voltags);
  494. if (error)
  495. goto done;
  496. /*
  497. * Fill in the user status array.
  498. */
  499. st_hdr = (struct read_element_status_header *)data;
  500. pg_hdr = (struct read_element_status_page_header *) (st_hdr + 1);
  501. avail = _2btol(st_hdr->count);
  502. if (avail != sc->sc_counts[chet]) {
  503. error = EINVAL;
  504. goto done;
  505. }
  506. user_data = mallocarray(avail, sizeof(struct changer_element_status),
  507. M_DEVBUF, M_WAITOK | M_ZERO);
  508. udsize = avail * sizeof(struct changer_element_status);
  509. desc = (caddr_t)(pg_hdr + 1);
  510. for (i = 0; i < avail; ++i) {
  511. struct changer_element_status *ces = &(user_data[i]);
  512. copy_element_status(pg_hdr->flags,
  513. (struct read_element_status_descriptor *)desc, ces);
  514. desc += desclen;
  515. }
  516. /* Copy array out to userspace. */
  517. error = copyout(user_data, cesr->cesr_data, udsize);
  518. done:
  519. if (data != NULL)
  520. dma_free(data, size);
  521. if (user_data != NULL)
  522. free(user_data, M_DEVBUF, 0);
  523. return (error);
  524. }
  525. int
  526. ch_getelemstatus(struct ch_softc *sc, int first, int count, caddr_t data,
  527. size_t datalen, int voltag)
  528. {
  529. struct scsi_read_element_status *cmd;
  530. struct scsi_xfer *xs;
  531. int error;
  532. /*
  533. * Build SCSI command.
  534. */
  535. xs = scsi_xs_get(sc->sc_link, SCSI_DATA_IN);
  536. if (xs == NULL)
  537. return (ENOMEM);
  538. xs->cmdlen = sizeof(*cmd);
  539. xs->data = data;
  540. xs->datalen = datalen;
  541. xs->retries = CHRETRIES;
  542. xs->timeout = 100000;
  543. cmd = (struct scsi_read_element_status *)xs->cmd;
  544. cmd->opcode = READ_ELEMENT_STATUS;
  545. _lto2b(first, cmd->sea);
  546. _lto2b(count, cmd->count);
  547. _lto3b(datalen, cmd->len);
  548. if (voltag)
  549. cmd->byte2 |= READ_ELEMENT_STATUS_VOLTAG;
  550. error = scsi_xs_sync(xs);
  551. scsi_xs_put(xs);
  552. return (error);
  553. }
  554. /*
  555. * Ask the device about itself and fill in the parameters in our
  556. * softc.
  557. */
  558. int
  559. ch_get_params(struct ch_softc *sc, int flags)
  560. {
  561. union scsi_mode_sense_buf *data;
  562. struct page_element_address_assignment *ea;
  563. struct page_device_capabilities *cap;
  564. int error, from;
  565. u_int8_t *moves, *exchanges;
  566. data = dma_alloc(sizeof(*data), PR_NOWAIT);
  567. if (data == NULL)
  568. return (ENOMEM);
  569. /*
  570. * Grab info from the element address assignment page (0x1d).
  571. */
  572. error = scsi_do_mode_sense(sc->sc_link, 0x1d, data,
  573. (void **)&ea, NULL, NULL, NULL, sizeof(*ea), flags, NULL);
  574. if (error == 0 && ea == NULL)
  575. error = EIO;
  576. if (error != 0) {
  577. #ifdef CHANGER_DEBUG
  578. printf("%s: could not sense element address page\n",
  579. sc->sc_dev.dv_xname);
  580. #endif
  581. dma_free(data, sizeof(*data));
  582. return (error);
  583. }
  584. sc->sc_firsts[CHET_MT] = _2btol(ea->mtea);
  585. sc->sc_counts[CHET_MT] = _2btol(ea->nmte);
  586. sc->sc_firsts[CHET_ST] = _2btol(ea->fsea);
  587. sc->sc_counts[CHET_ST] = _2btol(ea->nse);
  588. sc->sc_firsts[CHET_IE] = _2btol(ea->fieea);
  589. sc->sc_counts[CHET_IE] = _2btol(ea->niee);
  590. sc->sc_firsts[CHET_DT] = _2btol(ea->fdtea);
  591. sc->sc_counts[CHET_DT] = _2btol(ea->ndte);
  592. /* XXX Ask for transport geometry page. */
  593. /*
  594. * Grab info from the capabilities page (0x1f).
  595. */
  596. error = scsi_do_mode_sense(sc->sc_link, 0x1f, data,
  597. (void **)&cap, NULL, NULL, NULL, sizeof(*cap), flags, NULL);
  598. if (cap == NULL)
  599. error = EIO;
  600. if (error != 0) {
  601. #ifdef CHANGER_DEBUG
  602. printf("%s: could not sense capabilities page\n",
  603. sc->sc_dev.dv_xname);
  604. #endif
  605. dma_free(data, sizeof(*data));
  606. return (error);
  607. }
  608. bzero(sc->sc_movemask, sizeof(sc->sc_movemask));
  609. bzero(sc->sc_exchangemask, sizeof(sc->sc_exchangemask));
  610. moves = &cap->move_from_mt;
  611. exchanges = &cap->exchange_with_mt;
  612. for (from = CHET_MT; from <= CHET_DT; ++from) {
  613. sc->sc_movemask[from] = moves[from];
  614. sc->sc_exchangemask[from] = exchanges[from];
  615. }
  616. sc->sc_link->flags |= SDEV_MEDIA_LOADED;
  617. dma_free(data, sizeof(*data));
  618. return (0);
  619. }
  620. void
  621. ch_get_quirks(struct ch_softc *sc, struct scsi_inquiry_data *inqbuf)
  622. {
  623. const struct chquirk *match;
  624. int priority;
  625. sc->sc_settledelay = 0;
  626. match = (const struct chquirk *)scsi_inqmatch(inqbuf,
  627. (caddr_t)chquirks,
  628. sizeof(chquirks) / sizeof(chquirks[0]),
  629. sizeof(chquirks[0]), &priority);
  630. if (priority != 0) {
  631. sc->sc_settledelay = match->cq_settledelay;
  632. }
  633. }
  634. /*
  635. * Look at the returned sense and act on the error and detirmine
  636. * The unix error number to pass back... (0 = report no error)
  637. * (-1 = continue processing)
  638. */
  639. int
  640. ch_interpret_sense(struct scsi_xfer *xs)
  641. {
  642. struct scsi_sense_data *sense = &xs->sense;
  643. struct scsi_link *sc_link = xs->sc_link;
  644. u_int8_t serr = sense->error_code & SSD_ERRCODE;
  645. u_int8_t skey = sense->flags & SSD_KEY;
  646. if (((sc_link->flags & SDEV_OPEN) == 0) ||
  647. (serr != SSD_ERRCODE_CURRENT && serr != SSD_ERRCODE_DEFERRED))
  648. return (scsi_interpret_sense(xs));
  649. switch (skey) {
  650. /*
  651. * We do custom processing in ch for the unit becoming ready case.
  652. * in this case we do not allow xs->retries to be decremented
  653. * only on the "Unit Becoming Ready" case. This is because tape
  654. * changers report "Unit Becoming Ready" when they rescan their
  655. * state (i.e. when the door got opened) and can take a long time
  656. * for large units. Rather than having a massive timeout for
  657. * all operations (which would cause other problems) we allow
  658. * changers to wait (but be interruptable with Ctrl-C) forever
  659. * as long as they are reporting that they are becoming ready.
  660. * all other cases are handled as per the default.
  661. */
  662. case SKEY_NOT_READY:
  663. if ((xs->flags & SCSI_IGNORE_NOT_READY) != 0)
  664. return (0);
  665. switch (ASC_ASCQ(sense)) {
  666. case SENSE_NOT_READY_BECOMING_READY:
  667. SC_DEBUG(sc_link, SDEV_DB1, ("not ready: busy (%#x)\n",
  668. sense->add_sense_code_qual));
  669. /* don't count this as a retry */
  670. xs->retries++;
  671. return (scsi_delay(xs, 1));
  672. default:
  673. return (scsi_interpret_sense(xs));
  674. }
  675. default:
  676. return (scsi_interpret_sense(xs));
  677. }
  678. }