The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


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

FreeBSD/Linux Kernel Cross Reference
sys/dev/ppbus/vpo.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 1997, 1998 Nicolas Souchu
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  *
   26  * $FreeBSD$
   27  *
   28  */
   29 
   30 #ifdef KERNEL
   31 #include <sys/param.h>
   32 #include <sys/systm.h>
   33 #include <sys/malloc.h>
   34 #include <sys/buf.h>
   35 
   36 #include <machine/clock.h>
   37 
   38 #endif  /* KERNEL */
   39 
   40 #include <cam/cam.h>
   41 #include <cam/cam_ccb.h>
   42 #include <cam/cam_sim.h>
   43 #include <cam/cam_xpt_sim.h>
   44 #include <cam/cam_debug.h>
   45 
   46 #include <cam/scsi/scsi_all.h>
   47 #include <cam/scsi/scsi_message.h>
   48 #include <cam/scsi/scsi_da.h>
   49 
   50 #ifdef  KERNEL
   51 #include <sys/kernel.h>
   52 #endif /*KERNEL */
   53 
   54 #include "opt_vpo.h"
   55 
   56 #include <dev/ppbus/ppbconf.h>
   57 #include <dev/ppbus/vpoio.h>
   58 
   59 struct vpo_sense {
   60         struct scsi_sense cmd;
   61         unsigned int stat;
   62         unsigned int count;
   63 };
   64 
   65 struct vpo_data {
   66         unsigned short vpo_unit;
   67 
   68         int vpo_stat;
   69         int vpo_count;
   70         int vpo_error;
   71 
   72         int vpo_isplus;
   73 
   74         struct cam_sim  *sim;
   75         struct cam_path *path;
   76 
   77         struct vpo_sense vpo_sense;
   78 
   79         struct vpoio_data vpo_io;       /* interface to low level functions */
   80 };
   81 
   82 /* cam related functions */
   83 static void     vpo_action(struct cam_sim *sim, union ccb *ccb);
   84 static void     vpo_poll(struct cam_sim *sim);
   85 
   86 static int      nvpo = 0;
   87 #define MAXVP0  8                       /* XXX not much better! */
   88 static struct vpo_data *vpodata[MAXVP0];
   89 
   90 #ifdef KERNEL
   91 
   92 /*
   93  * Make ourselves visible as a ppbus driver
   94  */
   95 static struct ppb_device        *vpoprobe(struct ppb_data *ppb);
   96 static int                      vpoattach(struct ppb_device *dev);
   97 
   98 static struct ppb_driver vpodriver = {
   99     vpoprobe, vpoattach, "vpo"
  100 };
  101 DATA_SET(ppbdriver_set, vpodriver);
  102 
  103 #endif /* KERNEL */
  104 
  105 /*
  106  * vpoprobe()
  107  *
  108  * Called by ppb_attachdevs().
  109  */
  110 static struct ppb_device *
  111 vpoprobe(struct ppb_data *ppb)
  112 {
  113         struct vpo_data *vpo;
  114         struct ppb_device *dev;
  115 
  116         if (nvpo >= MAXVP0) {
  117                 printf("vpo: Too many devices (max %d)\n", MAXVP0);
  118                 return(NULL);
  119         }
  120 
  121         vpo = (struct vpo_data *)malloc(sizeof(struct vpo_data),
  122                                                         M_DEVBUF, M_NOWAIT);
  123         if (!vpo) {
  124                 printf("vpo: cannot malloc!\n");
  125                 return(NULL);
  126         }
  127         bzero(vpo, sizeof(struct vpo_data));
  128 
  129         vpodata[nvpo] = vpo;
  130 
  131         /* vpo dependent initialisation */
  132         vpo->vpo_unit = nvpo;
  133 
  134         /* ok, go to next device on next probe */
  135         nvpo ++;
  136 
  137         /* low level probe */
  138         vpoio_set_unit(&vpo->vpo_io, vpo->vpo_unit);
  139 
  140         /* check ZIP before ZIP+ or imm_probe() will send controls to
  141          * the printer or whatelse connected to the port */
  142         if ((dev = vpoio_probe(ppb, &vpo->vpo_io))) {
  143                 vpo->vpo_isplus = 0;
  144         } else if ((dev = imm_probe(ppb, &vpo->vpo_io))) {
  145                 vpo->vpo_isplus = 1;
  146         } else {
  147                 free(vpo, M_DEVBUF);
  148                 return (NULL);
  149         }
  150 
  151         return (dev);
  152 }
  153 
  154 /*
  155  * vpoattach()
  156  *
  157  * Called by ppb_attachdevs().
  158  */
  159 static int
  160 vpoattach(struct ppb_device *dev)
  161 {
  162         struct vpo_data *vpo = vpodata[dev->id_unit];
  163         struct cam_devq *devq;
  164 
  165         /* low level attachment */
  166         if (vpo->vpo_isplus) {
  167                 if (!imm_attach(&vpo->vpo_io))
  168                         return (0);
  169         } else {
  170                 if (!vpoio_attach(&vpo->vpo_io))
  171                         return (0);
  172         }
  173 
  174         /*
  175         **      Now tell the generic SCSI layer
  176         **      about our bus.
  177         */
  178         devq = cam_simq_alloc(/*maxopenings*/1);
  179         /* XXX What about low-level detach on error? */
  180         if (devq == NULL)
  181                 return (0);
  182 
  183         vpo->sim = cam_sim_alloc(vpo_action, vpo_poll, "vpo", vpo, dev->id_unit,
  184                                  /*untagged*/1, /*tagged*/0, devq);
  185         if (vpo->sim == NULL) {
  186                 cam_simq_free(devq);
  187                 return (0);
  188         }
  189 
  190         if (xpt_bus_register(vpo->sim, /*bus*/0) != CAM_SUCCESS) {
  191                 cam_sim_free(vpo->sim, /*free_devq*/TRUE);
  192                 return (0);
  193         }
  194 
  195         if (xpt_create_path(&vpo->path, /*periph*/NULL,
  196                             cam_sim_path(vpo->sim), CAM_TARGET_WILDCARD,
  197                             CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
  198                 xpt_bus_deregister(cam_sim_path(vpo->sim));
  199                 cam_sim_free(vpo->sim, /*free_devq*/TRUE);
  200                 return (0);
  201         }
  202 
  203         /* all went ok */
  204 
  205         return (1);
  206 }
  207 
  208 /*
  209  * vpo_intr()
  210  */
  211 static void
  212 vpo_intr(struct vpo_data *vpo, struct ccb_scsiio *csio)
  213 {
  214         int errno;      /* error in errno.h */
  215         int s;
  216 #ifdef VP0_DEBUG
  217         int i;
  218 #endif
  219 
  220         s = splcam();
  221 
  222         if (vpo->vpo_isplus) {
  223                 errno = imm_do_scsi(&vpo->vpo_io, VP0_INITIATOR,
  224                         csio->ccb_h.target_id,
  225                         (char *)&csio->cdb_io.cdb_bytes, csio->cdb_len,
  226                         (char *)csio->data_ptr, csio->dxfer_len,
  227                         &vpo->vpo_stat, &vpo->vpo_count, &vpo->vpo_error);
  228         } else {
  229                 errno = vpoio_do_scsi(&vpo->vpo_io, VP0_INITIATOR,
  230                         csio->ccb_h.target_id,
  231                         (char *)&csio->cdb_io.cdb_bytes, csio->cdb_len,
  232                         (char *)csio->data_ptr, csio->dxfer_len,
  233                         &vpo->vpo_stat, &vpo->vpo_count, &vpo->vpo_error);
  234         }
  235 
  236 #ifdef VP0_DEBUG
  237         printf("vpo_do_scsi = %d, status = 0x%x, count = %d, vpo_error = %d\n", 
  238                  errno, vpo->vpo_stat, vpo->vpo_count, vpo->vpo_error);
  239 
  240         /* dump of command */
  241         for (i=0; i<csio->cdb_len; i++)
  242                 printf("%x ", ((char *)&csio->cdb_io.cdb_bytes)[i]);
  243 
  244         printf("\n");
  245 #endif
  246 
  247         if (errno) {
  248                 /* connection to ppbus interrupted */
  249                 csio->ccb_h.status = CAM_CMD_TIMEOUT;
  250                 goto error;
  251         }
  252 
  253         /* if a timeout occured, no sense */
  254         if (vpo->vpo_error) {
  255                 if (vpo->vpo_error != VP0_ESELECT_TIMEOUT)
  256                         printf("vpo%d: VP0 error/timeout (%d)\n",
  257                                 vpo->vpo_unit, vpo->vpo_error);
  258 
  259                 csio->ccb_h.status = CAM_CMD_TIMEOUT;
  260                 goto error;
  261         }
  262 
  263         /* check scsi status */
  264         if (vpo->vpo_stat != SCSI_STATUS_OK) {
  265            csio->scsi_status = vpo->vpo_stat;
  266 
  267            /* check if we have to sense the drive */
  268            if ((vpo->vpo_stat & SCSI_STATUS_CHECK_COND) != 0) {
  269 
  270                 vpo->vpo_sense.cmd.opcode = REQUEST_SENSE;
  271                 vpo->vpo_sense.cmd.length = csio->sense_len;
  272                 vpo->vpo_sense.cmd.control = 0;
  273 
  274                 if (vpo->vpo_isplus) {
  275                         errno = imm_do_scsi(&vpo->vpo_io, VP0_INITIATOR,
  276                                 csio->ccb_h.target_id,
  277                                 (char *)&vpo->vpo_sense.cmd,
  278                                 sizeof(vpo->vpo_sense.cmd),
  279                                 (char *)&csio->sense_data, csio->sense_len,
  280                                 &vpo->vpo_sense.stat, &vpo->vpo_sense.count,
  281                                 &vpo->vpo_error);
  282                 } else {
  283                         errno = vpoio_do_scsi(&vpo->vpo_io, VP0_INITIATOR,
  284                                 csio->ccb_h.target_id,
  285                                 (char *)&vpo->vpo_sense.cmd,
  286                                 sizeof(vpo->vpo_sense.cmd),
  287                                 (char *)&csio->sense_data, csio->sense_len,
  288                                 &vpo->vpo_sense.stat, &vpo->vpo_sense.count,
  289                                 &vpo->vpo_error);
  290                 }
  291                         
  292 
  293 #ifdef VP0_DEBUG
  294                 printf("(sense) vpo_do_scsi = %d, status = 0x%x, count = %d, vpo_error = %d\n", 
  295                         errno, vpo->vpo_sense.stat, vpo->vpo_sense.count, vpo->vpo_error);
  296 #endif
  297 
  298                 /* check sense return status */
  299                 if (errno == 0 && vpo->vpo_sense.stat == SCSI_STATUS_OK) {
  300                    /* sense ok */
  301                    csio->ccb_h.status = CAM_AUTOSNS_VALID | CAM_SCSI_STATUS_ERROR;
  302                    csio->sense_resid = csio->sense_len - vpo->vpo_sense.count;
  303 
  304 #ifdef VP0_DEBUG
  305                    /* dump of sense info */
  306                    printf("(sense) ");
  307                    for (i=0; i<vpo->vpo_sense.count; i++)
  308                         printf("%x ", ((char *)&csio->sense_data)[i]);
  309                    printf("\n");
  310 #endif
  311 
  312                 } else {
  313                    /* sense failed */
  314                    csio->ccb_h.status = CAM_AUTOSENSE_FAIL;
  315                 }
  316            } else {
  317                 /* no sense */
  318                 csio->ccb_h.status = CAM_SCSI_STATUS_ERROR;                     
  319            }
  320 
  321            goto error;
  322         }
  323 
  324         csio->resid = csio->dxfer_len - vpo->vpo_count;
  325         csio->ccb_h.status = CAM_REQ_CMP;
  326 
  327 error:
  328         splx(s);
  329 
  330         return;
  331 }
  332 
  333 static void
  334 vpo_action(struct cam_sim *sim, union ccb *ccb)
  335 {
  336 
  337         struct vpo_data *vpo = (struct vpo_data *)sim->softc;
  338 
  339         switch (ccb->ccb_h.func_code) {
  340         case XPT_SCSI_IO:
  341         {
  342                 struct ccb_scsiio *csio;
  343 
  344                 csio = &ccb->csio;
  345 
  346 #ifdef VP0_DEBUG
  347                 printf("vpo%d: XPT_SCSI_IO (0x%x) request\n",
  348                         vpo->vpo_unit, csio->cdb_io.cdb_bytes[0]);
  349 #endif
  350                 
  351                 vpo_intr(vpo, csio);
  352 
  353                 xpt_done(ccb);
  354 
  355                 break;
  356         }
  357         case XPT_CALC_GEOMETRY:
  358         {
  359                 struct    ccb_calc_geometry *ccg;
  360                 u_int32_t secs_per_cylinder;
  361 
  362                 ccg = &ccb->ccg;
  363 
  364 #ifdef VP0_DEBUG
  365                 printf("vpo%d: XPT_CALC_GEOMETRY (%d, %d) request\n",
  366                         vpo->vpo_unit, ccg->volume_size, ccg->block_size);
  367 #endif
  368                 
  369                 ccg->heads = 64;
  370                 ccg->secs_per_track = 32;
  371 
  372                 secs_per_cylinder = ccg->heads * ccg->secs_per_track;
  373                 ccg->cylinders = ccg->volume_size / secs_per_cylinder;
  374 
  375                 ccb->ccb_h.status = CAM_REQ_CMP;
  376                 xpt_done(ccb);
  377                 break;
  378         }
  379         case XPT_RESET_BUS:             /* Reset the specified SCSI bus */
  380         {
  381 
  382 #ifdef VP0_DEBUG
  383                 printf("vpo%d: XPT_RESET_BUS request\n", vpo->vpo_unit);
  384 #endif
  385 
  386                 if (vpo->vpo_isplus) {
  387                         if (imm_reset_bus(&vpo->vpo_io)) {
  388                                 ccb->ccb_h.status = CAM_REQ_CMP_ERR;
  389                                 xpt_done(ccb);
  390                                 return;
  391                         }
  392                 } else {
  393                         if (vpoio_reset_bus(&vpo->vpo_io)) {
  394                                 ccb->ccb_h.status = CAM_REQ_CMP_ERR;
  395                                 xpt_done(ccb);
  396                                 return;
  397                         }
  398                 }
  399 
  400                 ccb->ccb_h.status = CAM_REQ_CMP;
  401                 xpt_done(ccb);
  402                 break;
  403         }
  404         case XPT_PATH_INQ:              /* Path routing inquiry */
  405         {
  406                 struct ccb_pathinq *cpi = &ccb->cpi;
  407                 
  408 #ifdef VP0_DEBUG
  409                 printf("vpo%d: XPT_PATH_INQ request\n", vpo->vpo_unit);
  410 #endif
  411                 cpi->version_num = 1; /* XXX??? */
  412                 cpi->hba_inquiry = 0;
  413                 cpi->target_sprt = 0;
  414                 cpi->hba_misc = 0;
  415                 cpi->hba_eng_cnt = 0;
  416                 cpi->max_target = 7;
  417                 cpi->max_lun = 0;
  418                 cpi->initiator_id = VP0_INITIATOR;
  419                 cpi->bus_id = sim->bus_id;
  420                 cpi->base_transfer_speed = 93;
  421                 strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
  422                 strncpy(cpi->hba_vid, "Iomega", HBA_IDLEN);
  423                 strncpy(cpi->dev_name, sim->sim_name, DEV_IDLEN);
  424                 cpi->unit_number = sim->unit_number;
  425 
  426                 cpi->ccb_h.status = CAM_REQ_CMP;
  427                 xpt_done(ccb);
  428                 break;
  429         }
  430         default:
  431                 ccb->ccb_h.status = CAM_REQ_INVALID;
  432                 xpt_done(ccb);
  433                 break;
  434         }
  435 
  436         return;
  437 }
  438 
  439 static void
  440 vpo_poll(struct cam_sim *sim)
  441 {       
  442         /* The ZIP is actually always polled throw vpo_action() */
  443         return;
  444 }

Cache object: a87692a590672729b4e16966259fee54


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


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.