sdscsi.c - vx32 - Local 9vx git repository for patches.
git clone git://r-36.net/vx32
Log
Files
Refs
---
sdscsi.c (7937B)
---
     1 #include "u.h"
     2 #include "lib.h"
     3 #include "mem.h"
     4 #include "dat.h"
     5 #include "fns.h"
     6 #include "io.h"
     7 #include "ureg.h"
     8 #include "error.h"
     9 
    10 #include "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         status = 0;
    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->perm.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