2 * Copyright (c) 1998,1999,2000
3 * Traakan, Inc., Los Altos, CA
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice unmodified, this list of conditions, and the following
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
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
20 * FOR 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
38 #include "ndmagents.h"
41 #ifndef NDMOS_OPTION_NO_CONTROL_AGENT
45 ndmca_robot_issue_scsi_req (struct smc_ctrl_block *smc)
47 struct ndmconn * conn = (struct ndmconn *) smc->app_data;
48 struct smc_scsi_req * sr = &smc->scsi_req;
51 rc = ndmscsi_execute (conn, (struct ndmscsi_request *) sr, 0);
57 ndmca_robot_prep_target (struct ndm_session *sess)
59 struct smc_ctrl_block * smc = &sess->control_acb.smc_cb;
62 NDMOS_MACRO_ZEROFILL (smc);
64 smc->app_data = sess->plumb.robot;
65 smc->issue_scsi_req = ndmca_robot_issue_scsi_req;
67 rc = ndmscsi_use (sess->plumb.robot,
68 &sess->control_acb.job.robot_target);
75 ndmca_robot_obtain_info (struct ndm_session *sess)
77 struct smc_ctrl_block * smc = &sess->control_acb.smc_cb;
80 rc = smc_inquire (smc);
83 rc = smc_get_elem_aa (smc);
86 rc = smc_read_elem_status (smc);
93 ndmca_robot_init_elem_status (struct ndm_session *sess)
95 struct smc_ctrl_block * smc = &sess->control_acb.smc_cb;
99 "Commanding robot to initialize element status (take inventory)");
101 rc = smc_init_elem_status (smc);
103 ndmalogf (sess, 0, 0, "init-elem-status failed");
111 ndmca_robot_startup (struct ndm_session *sess)
115 if (!sess->control_acb.job.have_robot)
116 return -1; /* Huh? why were we called */
118 rc = ndmca_connect_robot_agent(sess);
121 rc = ndmca_robot_prep_target(sess);
128 ndmca_robot_move (struct ndm_session *sess, int src_addr, int dst_addr)
130 struct ndm_control_agent *ca = &sess->control_acb;
131 struct smc_ctrl_block * smc = &ca->smc_cb;
135 ndmalogf (sess, 0, 2, "robot moving @%d to @%d",
139 for (t = 0; t <= ca->job.robot_timeout; t += 10) {
141 ndmalogf (sess, 0, 2,
142 "Pausing ten seconds before retry (%d/%d)",
143 t, ca->job.robot_timeout);
146 rc = smc_move (smc, src_addr, dst_addr,
147 0, smc->elem_aa.mte_addr);
152 ndmalogf (sess, 0, 2, "robot move OK @%d to @%d",
155 ndmalogf (sess, 0, 2, "robot move BAD @%d to @%d",
163 ndmca_robot_load (struct ndm_session *sess, int slot_addr)
165 struct smc_ctrl_block * smc = &sess->control_acb.smc_cb;
166 unsigned dte_addr = smc->elem_aa.dte_addr;
169 if (sess->control_acb.job.drive_addr_given)
170 dte_addr = sess->control_acb.job.drive_addr;
172 ndmalogf (sess, 0, 1,
173 "Commanding robot to load slot @%d into drive @%d",
174 slot_addr, dte_addr);
176 rc = ndmca_robot_move (sess, slot_addr, dte_addr);
182 ndmca_robot_unload (struct ndm_session *sess, int slot_addr)
184 struct smc_ctrl_block * smc = &sess->control_acb.smc_cb;
185 int dte_addr = smc->elem_aa.dte_addr;
188 if (sess->control_acb.job.drive_addr_given)
189 dte_addr = sess->control_acb.job.drive_addr;
191 /* tricky part -- some (most?) robots need the drive to eject */
193 ndmalogf (sess, 0, 1,
194 "Commanding robot to unload drive @%d to slot @%d",
195 dte_addr, slot_addr);
197 rc = ndmca_robot_move (sess, dte_addr, slot_addr);
203 struct smc_element_descriptor *
204 ndmca_robot_find_element (struct ndm_session *sess, int element_address)
206 struct smc_ctrl_block * smc = &sess->control_acb.smc_cb;
208 struct smc_element_descriptor * edp;
210 for (i = 0; i < smc->n_elem_desc; i++) {
211 edp = &smc->elem_desc[i];
212 if (edp->element_address == element_address)
220 ndmca_robot_check_ready (struct ndm_session *sess)
222 struct smc_ctrl_block * smc = &sess->control_acb.smc_cb;
223 unsigned first_dte_addr;
228 struct smc_element_descriptor * edp;
230 rc = ndmca_robot_obtain_info (sess);
233 if (sess->control_acb.job.remedy_all) {
234 first_dte_addr = smc->elem_aa.dte_addr;
235 n_dte_addr = smc->elem_aa.dte_count;
238 if (sess->control_acb.job.drive_addr_given) {
239 first_dte_addr = sess->control_acb.job.drive_addr;
241 first_dte_addr = smc->elem_aa.dte_addr;
245 for (i = 0; i < n_dte_addr; i++) {
246 edp = ndmca_robot_find_element (sess, first_dte_addr+i);
251 ndmalogf (sess, 0, 1, "tape drive @%d not empty",
252 edp->element_address);
260 ndmca_robot_remedy_ready (struct ndm_session *sess)
262 struct smc_ctrl_block * smc = &sess->control_acb.smc_cb;
266 struct smc_element_descriptor * edp;
267 struct smc_element_descriptor * edp2;
268 unsigned first_dte_addr;
274 rc = ndmca_robot_obtain_info (sess);
277 if (sess->control_acb.job.remedy_all) {
278 first_dte_addr = smc->elem_aa.dte_addr;
279 n_dte_addr = smc->elem_aa.dte_count;
282 if (sess->control_acb.job.drive_addr_given) {
283 first_dte_addr = sess->control_acb.job.drive_addr;
285 first_dte_addr = smc->elem_aa.dte_addr;
289 for (i = 0; i < n_dte_addr; i++) {
290 edp = ndmca_robot_find_element (sess, first_dte_addr+i);
295 sprintf (prefix, "drive @%d not empty", edp->element_address);
298 ndmalogf (sess, 0, 1, "%s, invalid source", prefix);
303 sprintf (NDMOS_API_STREND(prefix), ", src @%d",
306 edp2 = ndmca_robot_find_element (sess, edp->src_se_addr);
308 if (edp2->element_type_code != SMC_ELEM_TYPE_SE) {
309 ndmalogf (sess, 0, 1, "%s, not slot", prefix);
315 ndmalogf (sess, 0, 1, "%s, but slot Full", prefix);
320 rc = ndmca_robot_move (sess,
321 edp->element_address, edp->src_se_addr);
323 ndmalogf (sess, 0, 1, "%s, move failed", prefix);
335 * ndmca_robot_query() incrementally obtains info so that we
336 * can print progress.
340 ndmca_robot_query (struct ndm_session *sess)
342 struct smc_ctrl_block * smc = &sess->control_acb.smc_cb;
347 int lineno, nline = 1;
349 ndmalogqr (sess, " Type");
351 rc = smc_inquire (smc);
353 ndmalogqr (sess, " ERROR smc_inquire(): %s", smc->errmsg);
355 ndmalogqr (sess, " '%s'", smc->ident);
359 ndmalogqr (sess, " Elements");
360 rc = smc_get_elem_aa (smc);
362 ndmalogqr (sess, " ERROR smc_get_elem_aa(): %s", smc->errmsg);
365 for (lineno = 0, nline = 1; lineno < nline; lineno++) {
366 rc = smc_pp_element_address_assignments (&smc->elem_aa,
369 strcpy (buf, "PP-ERROR");
372 ndmalogqr (sess, "%s %s", lnbuf, buf);
376 ndmalogqr (sess, " Status");
377 rc = smc_read_elem_status (smc);
379 ndmalogqr (sess, " ERROR smc_read_elem_status(): %s", smc->errmsg);
381 ndmalogqr (sess, " E# Addr Type Status");
382 ndmalogqr (sess, " -- ---- ---- ---------------------");
383 for (i = 0; i < smc->n_elem_desc; i++) {
384 struct smc_element_descriptor * edp;
386 edp = &smc->elem_desc[i];
388 for (lineno = 0, nline = 1; lineno < nline; lineno++) {
389 rc = smc_pp_element_descriptor (edp,
393 sprintf (lnbuf, " %2d ", i+1);
395 sprintf (lnbuf, " ");
398 strcpy (buf, "PP-ERROR");
401 ndmalogqr (sess, "%s %s", lnbuf, buf);
411 ndmca_robot_verify_media (struct ndm_session *sess)
413 struct smc_ctrl_block * smc = &sess->control_acb.smc_cb;
414 struct ndm_media_table *mtab = &sess->control_acb.job.media_tab;
416 struct ndmmedia * me;
417 struct smc_element_descriptor *edp;
422 rc = ndmca_robot_obtain_info (sess);
425 for (i = 0; i < mtab->n_media; i++) {
426 me = &mtab->media[i];
428 if (! me->valid_slot) {
429 me->slot_missing = 1;
431 continue; /* what now */
434 for (j = 0; j < smc->n_elem_desc; j++) {
435 edp = &smc->elem_desc[j];
437 if (edp->element_type_code != SMC_ELEM_TYPE_SE)
440 if (edp->element_address != me->slot_addr)
451 if (j >= smc->n_elem_desc) {
461 * For NDM_JOB_OP_LIST_LABELS, fill in media_tab based on non-empty slots.
462 * Note: this might REALLY nerf on a cleaning cartridge.
466 ndmca_robot_synthesize_media (struct ndm_session *sess)
468 struct smc_ctrl_block * smc = &sess->control_acb.smc_cb;
469 struct ndm_media_table *mtab = &sess->control_acb.job.media_tab;
471 struct ndmmedia * me;
472 struct smc_element_descriptor *edp;
475 rc = ndmca_robot_obtain_info (sess);
478 for (i = 0; i < smc->n_elem_desc; i++) {
479 edp = &smc->elem_desc[i];
481 if (edp->element_type_code != SMC_ELEM_TYPE_SE)
487 me = &mtab->media[mtab->n_media++];
488 NDMOS_MACRO_ZEROFILL (me);
491 me->slot_addr = edp->element_address;
496 #endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */