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/pc/sdscsi.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 #include "u.h"
    2 #include "../port/lib.h"
    3 #include "mem.h"
    4 #include "dat.h"
    5 #include "fns.h"
    6 #include "io.h"
    7 #include "ureg.h"
    8 #include "../port/error.h"
    9 
   10 #include "../port/sd.h"
   11 
   12 static int
   13 scsitest(SDreq* r)
   14 {
   15         r->write = 0;
   16         memset(r->cmd, 0, sizeof(r->cmd));
   17         r->cmd[1] = r->lun<<5;
   18         r->clen = 6;
   19         r->data = nil;
   20         r->dlen = 0;
   21         r->flags = 0;
   22 
   23         r->status = ~0;
   24 
   25         return r->unit->dev->ifc->rio(r);
   26 }
   27 
   28 int
   29 scsiverify(SDunit* unit)
   30 {
   31         SDreq *r;
   32         int i, status;
   33         uchar *inquiry;
   34 
   35         if((r = malloc(sizeof(SDreq))) == nil)
   36                 return 0;
   37         if((inquiry = sdmalloc(sizeof(unit->inquiry))) == nil){
   38                 free(r);
   39                 return 0;
   40         }
   41         r->unit = unit;
   42         r->lun = 0;             /* ??? */
   43 
   44         memset(unit->inquiry, 0, sizeof(unit->inquiry));
   45         r->write = 0;
   46         r->cmd[0] = 0x12;
   47         r->cmd[1] = r->lun<<5;
   48         r->cmd[4] = sizeof(unit->inquiry)-1;
   49         r->clen = 6;
   50         r->data = inquiry;
   51         r->dlen = sizeof(unit->inquiry)-1;
   52         r->flags = 0;
   53 
   54         r->status = ~0;
   55         if(unit->dev->ifc->rio(r) != SDok){
   56                 free(r);
   57                 return 0;
   58         }
   59         memmove(unit->inquiry, inquiry, r->dlen);
   60         free(inquiry);
   61 
   62         SET(status);
   63         for(i = 0; i < 3; i++){
   64                 while((status = scsitest(r)) == SDbusy)
   65                         ;
   66                 if(status == SDok || status != SDcheck)
   67                         break;
   68                 if(!(r->flags & SDvalidsense))
   69                         break;
   70                 if((r->sense[2] & 0x0F) != 0x02)
   71                         continue;
   72 
   73                 /*
   74                  * Unit is 'not ready'.
   75                  * If it is in the process of becoming ready or needs
   76                  * an initialising command, set status so it will be spun-up
   77                  * below.
   78                  * If there's no medium, that's OK too, but don't
   79                  * try to spin it up.
   80                  */
   81                 if(r->sense[12] == 0x04){
   82                         if(r->sense[13] == 0x02 || r->sense[13] == 0x01){
   83                                 status = SDok;
   84                                 break;
   85                         }
   86                 }
   87                 if(r->sense[12] == 0x3A)
   88                         break;
   89         }
   90 
   91         if(status == SDok){
   92                 /*
   93                  * Try to ensure a direct-access device is spinning.
   94                  * Don't wait for completion, ignore the result.
   95                  */
   96                 if((unit->inquiry[0] & 0x1F) == 0){
   97                         memset(r->cmd, 0, sizeof(r->cmd));
   98                         r->write = 0;
   99                         r->cmd[0] = 0x1B;
  100                         r->cmd[1] = (r->lun<<5)|0x01;
  101                         r->cmd[4] = 1;
  102                         r->clen = 6;
  103                         r->data = nil;
  104                         r->dlen = 0;
  105                         r->flags = 0;
  106 
  107                         r->status = ~0;
  108                         unit->dev->ifc->rio(r);
  109                 }
  110         }
  111         free(r);
  112 
  113         if(status == SDok || status == SDcheck)
  114                 return 1;
  115         return 0;
  116 }
  117 
  118 static int
  119 scsirio(SDreq* r)
  120 {
  121         /*
  122          * Perform an I/O request, returning
  123          *      -1      failure
  124          *       0      ok
  125          *       1      no medium present
  126          *       2      retry
  127          * The contents of r may be altered so the
  128          * caller should re-initialise if necesary.
  129          */
  130         r->status = ~0;
  131         switch(r->unit->dev->ifc->rio(r)){
  132         default:
  133                 break;
  134         case SDcheck:
  135                 if(!(r->flags & SDvalidsense))
  136                         break;
  137                 switch(r->sense[2] & 0x0F){
  138                 case 0x00:              /* no sense */
  139                 case 0x01:              /* recovered error */
  140                         return 2;
  141                 case 0x06:              /* check condition */
  142                         /*
  143                          * 0x28 - not ready to ready transition,
  144                          *        medium may have changed.
  145                          * 0x29 - power on or some type of reset.
  146                          */
  147                         if(r->sense[12] == 0x28 && r->sense[13] == 0)
  148                                 return 2;
  149                         if(r->sense[12] == 0x29)
  150                                 return 2;
  151                         break;
  152                 case 0x02:              /* not ready */
  153                         /*
  154                          * If no medium present, bail out.
  155                          * If unit is becoming ready, rather than not
  156                          * not ready, wait a little then poke it again.                                  */
  157                         if(r->sense[12] == 0x3A)
  158                                 break;
  159                         if(r->sense[12] != 0x04 || r->sense[13] != 0x01)
  160                                 break;
  161 
  162                         while(waserror())
  163                                 ;
  164                         tsleep(&up->sleep, return0, 0, 500);
  165                         poperror();
  166                         scsitest(r);
  167                         return 2;
  168                 default:
  169                         break;
  170                 }
  171                 break;
  172         case SDok:
  173                 return 0;
  174         }
  175         return -1;
  176 }
  177 
  178 int
  179 scsionline(SDunit* unit)
  180 {
  181         SDreq *r;
  182         uchar *p;
  183         int ok, retries;
  184 
  185         if((r = malloc(sizeof(SDreq))) == nil)
  186                 return 0;
  187         if((p = sdmalloc(8)) == nil){
  188                 free(r);
  189                 return 0;
  190         }
  191 
  192         ok = 0;
  193 
  194         r->unit = unit;
  195         r->lun = 0;                             /* ??? */
  196         for(retries = 0; retries < 10; retries++){
  197                 /*
  198                  * Read-capacity is mandatory for DA, WORM, CD-ROM and
  199                  * MO. It may return 'not ready' if type DA is not
  200                  * spun up, type MO or type CD-ROM are not loaded or just
  201                  * plain slow getting their act together after a reset.
  202                  */
  203                 r->write = 0;
  204                 memset(r->cmd, 0, sizeof(r->cmd));
  205                 r->cmd[0] = 0x25;
  206                 r->cmd[1] = r->lun<<5;
  207                 r->clen = 10;
  208                 r->data = p;
  209                 r->dlen = 8;
  210                 r->flags = 0;
  211 
  212                 r->status = ~0;
  213                 switch(scsirio(r)){
  214                 default:
  215                         break;
  216                 case 0:
  217                         unit->sectors = (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3];
  218                         unit->secsize = (p[4]<<24)|(p[5]<<16)|(p[6]<<8)|p[7];
  219 
  220                         /*
  221                          * Some ATAPI CD readers lie about the block size.
  222                          * Since we don't read audio via this interface
  223                          * it's okay to always fudge this.
  224                          */
  225                         if(unit->secsize == 2352)
  226                                 unit->secsize = 2048;
  227                         /*
  228                          * Devices with removable media may return 0 sectors
  229                          * when they have empty media (e.g. sata dvd writers);
  230                          * if so, keep the count zero.
  231                          *
  232                          * Read-capacity returns the LBA of the last sector,
  233                          * therefore the number of sectors must be incremented.
  234                          */
  235                         if(unit->sectors != 0)
  236                                 unit->sectors++;
  237                         ok = 1;
  238                         break;
  239                 case 1:
  240                         ok = 1;
  241                         break;
  242                 case 2:
  243                         continue;
  244                 }
  245                 break;
  246         }
  247         free(p);
  248         free(r);
  249 
  250         if(ok)
  251                 return ok+retries;
  252         else
  253                 return 0;
  254 }
  255 
  256 int
  257 scsiexec(SDunit* unit, int write, uchar* cmd, int clen, void* data, int* dlen)
  258 {
  259         SDreq *r;
  260         int status;
  261 
  262         if((r = malloc(sizeof(SDreq))) == nil)
  263                 return SDmalloc;
  264         r->unit = unit;
  265         r->lun = cmd[1]>>5;             /* ??? */
  266         r->write = write;
  267         memmove(r->cmd, cmd, clen);
  268         r->clen = clen;
  269         r->data = data;
  270         if(dlen)
  271                 r->dlen = *dlen;
  272         r->flags = 0;
  273 
  274         r->status = ~0;
  275 
  276         /*
  277          * Call the device-specific I/O routine.
  278          * There should be no calls to 'error()' below this
  279          * which percolate back up.
  280          */
  281         switch(status = unit->dev->ifc->rio(r)){
  282         case SDok:
  283                 if(dlen)
  284                         *dlen = r->rlen;
  285                 /*FALLTHROUGH*/
  286         case SDcheck:
  287                 /*FALLTHROUGH*/
  288         default:
  289                 /*
  290                  * It's more complicated than this. There are conditions
  291                  * which are 'ok' but for which the returned status code
  292                  * is not 'SDok'.
  293                  * Also, not all conditions require a reqsense, might
  294                  * need to do a reqsense here and make it available to the
  295                  * caller somehow.
  296                  *
  297                  * MaƱana.
  298                  */
  299                 break;
  300         }
  301         sdfree(r);
  302 
  303         return status;
  304 }
  305 
  306 static void
  307 scsifmt10(SDreq *r, int write, int lun, ulong nb, uvlong bno)
  308 {
  309         uchar *c;
  310 
  311         c = r->cmd;
  312         if(write == 0)
  313                 c[0] = 0x28;
  314         else
  315                 c[0] = 0x2A;
  316         c[1] = lun<<5;
  317         c[2] = bno>>24;
  318         c[3] = bno>>16;
  319         c[4] = bno>>8;
  320         c[5] = bno;
  321         c[6] = 0;
  322         c[7] = nb>>8;
  323         c[8] = nb;
  324         c[9] = 0;
  325 
  326         r->clen = 10;
  327 }
  328 
  329 static void
  330 scsifmt16(SDreq *r, int write, int lun, ulong nb, uvlong bno)
  331 {
  332         uchar *c;
  333 
  334         c = r->cmd;
  335         if(write == 0)
  336                 c[0] = 0x88;
  337         else
  338                 c[0] = 0x8A;
  339         c[1] = lun<<5;          /* so wrong */
  340         c[2] = bno>>56;
  341         c[3] = bno>>48;
  342         c[4] = bno>>40;
  343         c[5] = bno>>32;
  344         c[6] = bno>>24;
  345         c[7] = bno>>16;
  346         c[8] = bno>>8;
  347         c[9] = bno;
  348         c[10] = nb>>24;
  349         c[11] = nb>>16;
  350         c[12] = nb>>8;
  351         c[13] = nb;
  352         c[14] = 0;
  353         c[15] = 0;
  354 
  355         r->clen = 16;
  356 }
  357 
  358 long
  359 scsibio(SDunit* unit, int lun, int write, void* data, long nb, uvlong bno)
  360 {
  361         SDreq *r;
  362         long rlen;
  363 
  364         if((r = malloc(sizeof(SDreq))) == nil)
  365                 error(Enomem);
  366         r->unit = unit;
  367         r->lun = lun;
  368 again:
  369         r->write = write;
  370         if(bno >= (1ULL<<32))
  371                 scsifmt16(r, write, lun, nb, bno);
  372         else
  373                 scsifmt10(r, write, lun, nb, bno);
  374         r->data = data;
  375         r->dlen = nb*unit->secsize;
  376         r->flags = 0;
  377 
  378         r->status = ~0;
  379         switch(scsirio(r)){
  380         default:
  381                 rlen = -1;
  382                 break;
  383         case 0:
  384                 rlen = r->rlen;
  385                 break;
  386         case 2:
  387                 rlen = -1;
  388                 if(!(r->flags & SDvalidsense))
  389                         break;
  390                 switch(r->sense[2] & 0x0F){
  391                 default:
  392                         break;
  393                 case 0x01:              /* recovered error */
  394                         print("%s: recovered error at sector %llud\n",
  395                                 unit->name, bno);
  396                         rlen = r->rlen;
  397                         break;
  398                 case 0x06:              /* check condition */
  399                         /*
  400                          * Check for a removeable media change.
  401                          * If so, mark it by zapping the geometry info
  402                          * to force an online request.
  403                          */
  404                         if(r->sense[12] != 0x28 || r->sense[13] != 0)
  405                                 break;
  406                         if(unit->inquiry[1] & 0x80)
  407                                 unit->sectors = 0;
  408                         break;
  409                 case 0x02:              /* not ready */
  410                         /*
  411                          * If unit is becoming ready,
  412                          * rather than not not ready, try again.
  413                          */
  414                         if(r->sense[12] == 0x04 && r->sense[13] == 0x01)
  415                                 goto again;
  416                         break;
  417                 }
  418                 break;
  419         }
  420         free(r);
  421 
  422         return rlen;
  423 }
  424 

Cache object: e5aeb434fe21cae43f72ca9076b23657


[ 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.