sdaoe.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651
  1. /*
  2. * aoe sd driver, copyright © 2007 coraid
  3. */
  4. #include "u.h"
  5. #include "../port/lib.h"
  6. #include "mem.h"
  7. #include "dat.h"
  8. #include "fns.h"
  9. #include "io.h"
  10. #include "../port/error.h"
  11. #include "../port/sd.h"
  12. #include "../port/netif.h"
  13. #include "../port/aoe.h"
  14. extern char Echange[];
  15. extern char Enotup[];
  16. #define uprint(...) snprint(up->genbuf, sizeof up->genbuf, __VA_ARGS__);
  17. enum {
  18. Nctlr = 32,
  19. Maxpath = 128,
  20. };
  21. enum {
  22. /* sync with ahci.h */
  23. Dllba = 1<<0,
  24. Dsmart = 1<<1,
  25. Dpower = 1<<2,
  26. Dnop = 1<<3,
  27. Datapi = 1<<4,
  28. Datapi16= 1<<5,
  29. };
  30. static char *flagname[] = {
  31. "llba",
  32. "smart",
  33. "power",
  34. "nop",
  35. "atapi",
  36. "atapi16",
  37. };
  38. typedef struct Ctlr Ctlr;
  39. struct Ctlr{
  40. QLock;
  41. Ctlr *next;
  42. SDunit *unit;
  43. char path[Maxpath];
  44. Chan *c;
  45. ulong vers;
  46. uchar mediachange;
  47. uchar flag;
  48. uchar smart;
  49. uchar smartrs;
  50. uchar feat;
  51. uvlong sectors;
  52. char serial[20+1];
  53. char firmware[8+1];
  54. char model[40+1];
  55. char ident[0x100];
  56. };
  57. static Lock ctlrlock;
  58. static Ctlr *head;
  59. static Ctlr *tail;
  60. SDifc sdaoeifc;
  61. static void
  62. idmove(char *p, ushort *a, int n)
  63. {
  64. int i;
  65. char *op, *e;
  66. op = p;
  67. for(i = 0; i < n/2; i++){
  68. *p++ = a[i] >> 8;
  69. *p++ = a[i];
  70. }
  71. *p = 0;
  72. while(p > op && *--p == ' ')
  73. *p = 0;
  74. e = p;
  75. p = op;
  76. while(*p == ' ')
  77. p++;
  78. memmove(op, p, n - (e - p));
  79. }
  80. static ushort
  81. gbit16(void *a)
  82. {
  83. uchar *i;
  84. i = a;
  85. return i[1] << 8 | i[0];
  86. }
  87. static ulong
  88. gbit32(void *a)
  89. {
  90. ulong j;
  91. uchar *i;
  92. i = a;
  93. j = i[3] << 24;
  94. j |= i[2] << 16;
  95. j |= i[1] << 8;
  96. j |= i[0];
  97. return j;
  98. }
  99. static uvlong
  100. gbit64(void *a)
  101. {
  102. uchar *i;
  103. i = a;
  104. return (uvlong)gbit32(i+4)<<32 | gbit32(i);
  105. }
  106. static int
  107. identify(Ctlr *c, ushort *id)
  108. {
  109. int i;
  110. uchar oserial[21];
  111. uvlong osectors, s;
  112. osectors = c->sectors;
  113. memmove(oserial, c->serial, sizeof c->serial);
  114. c->feat &= ~(Dllba|Dpower|Dsmart|Dnop);
  115. i = gbit16(id+83) | gbit16(id+86);
  116. if(i & (1<<10)){
  117. c->feat |= Dllba;
  118. s = gbit64(id+100);
  119. }else
  120. s = gbit32(id+60);
  121. i = gbit16(id+83);
  122. if((i>>14) == 1) {
  123. if(i & (1<<3))
  124. c->feat |= Dpower;
  125. i = gbit16(id+82);
  126. if(i & 1)
  127. c->feat |= Dsmart;
  128. if(i & (1<<14))
  129. c->feat |= Dnop;
  130. }
  131. idmove(c->serial, id+10, 20);
  132. idmove(c->firmware, id+23, 8);
  133. idmove(c->model, id+27, 40);
  134. if((osectors == 0 || osectors != s) &&
  135. memcmp(oserial, c->serial, sizeof oserial) != 0){
  136. c->sectors = s;
  137. c->mediachange = 1;
  138. c->vers++;
  139. }
  140. return 0;
  141. }
  142. /* must call with d qlocked */
  143. static int
  144. aoeidentify(Ctlr *d, SDunit *u)
  145. {
  146. Chan *c;
  147. c = nil;
  148. if(waserror()){
  149. if(c)
  150. cclose(c);
  151. iprint("aoeidentify: %s\n", up->errstr);
  152. nexterror();
  153. }
  154. uprint("%s/ident", d->path);
  155. c = namec(up->genbuf, Aopen, OREAD, 0);
  156. devtab[c->type]->read(c, d->ident, sizeof d->ident, 0);
  157. poperror();
  158. cclose(c);
  159. d->feat = 0;
  160. d->smart = 0;
  161. identify(d, (ushort*)d->ident);
  162. memset(u->inquiry, 0, sizeof u->inquiry);
  163. u->inquiry[2] = 2;
  164. u->inquiry[3] = 2;
  165. u->inquiry[4] = sizeof u->inquiry - 4;
  166. memmove(u->inquiry+8, d->model, 40);
  167. return 0;
  168. }
  169. static Ctlr*
  170. ctlrlookup(char *path)
  171. {
  172. Ctlr *c;
  173. lock(&ctlrlock);
  174. for(c = head; c; c = c->next)
  175. if(strcmp(c->path, path) == 0)
  176. break;
  177. unlock(&ctlrlock);
  178. return c;
  179. }
  180. static Ctlr*
  181. newctlr(char *path)
  182. {
  183. Ctlr *c;
  184. /* race? */
  185. if(ctlrlookup(path))
  186. error(Eexist);
  187. if((c = malloc(sizeof *c)) == nil)
  188. return 0;
  189. kstrcpy(c->path, path, sizeof c->path);
  190. lock(&ctlrlock);
  191. if(head != nil)
  192. tail->next = c;
  193. else
  194. head = c;
  195. tail = c;
  196. unlock(&ctlrlock);
  197. return c;
  198. }
  199. static void
  200. delctlr(Ctlr *c)
  201. {
  202. Ctlr *x, *prev;
  203. lock(&ctlrlock);
  204. for(prev = 0, x = head; x; prev = x, x = c->next)
  205. if(strcmp(c->path, x->path) == 0)
  206. break;
  207. if(x == 0){
  208. unlock(&ctlrlock);
  209. error(Enonexist);
  210. }
  211. if(prev)
  212. prev->next = x->next;
  213. else
  214. head = x->next;
  215. if(x->next == nil)
  216. tail = prev;
  217. unlock(&ctlrlock);
  218. if(x->c)
  219. cclose(x->c);
  220. free(x);
  221. }
  222. static SDev*
  223. aoeprobe(char *path, SDev *s)
  224. {
  225. int n, i;
  226. char *p;
  227. Chan *c;
  228. Ctlr *ctlr;
  229. if((p = strrchr(path, '/')) == 0)
  230. error(Ebadarg);
  231. *p = 0;
  232. uprint("%s/ctl", path);
  233. *p = '/';
  234. c = namec(up->genbuf, Aopen, OWRITE, 0);
  235. if(waserror()) {
  236. cclose(c);
  237. nexterror();
  238. }
  239. n = uprint("discover %s", p+1);
  240. devtab[c->type]->write(c, up->genbuf, n, 0);
  241. poperror();
  242. cclose(c);
  243. for(i = 0;; i += 200){
  244. if(i > 8000 || waserror())
  245. error(Etimedout);
  246. tsleep(&up->sleep, return0, 0, 200);
  247. poperror();
  248. uprint("%s/ident", path);
  249. if(waserror())
  250. continue;
  251. c = namec(up->genbuf, Aopen, OREAD, 0);
  252. poperror();
  253. cclose(c);
  254. ctlr = newctlr(path);
  255. break;
  256. }
  257. if(s == nil && (s = malloc(sizeof *s)) == nil)
  258. return nil;
  259. s->ctlr = ctlr;
  260. s->ifc = &sdaoeifc;
  261. s->nunit = 1;
  262. return s;
  263. }
  264. static char *probef[32];
  265. static int nprobe;
  266. static int
  267. pnpprobeid(char *s)
  268. {
  269. int id;
  270. if(strlen(s) < 2)
  271. return 0;
  272. id = 'e';
  273. if(s[1] == '!')
  274. id = s[0];
  275. return id;
  276. }
  277. static SDev*
  278. aoepnp(void)
  279. {
  280. int i, id;
  281. char *p;
  282. SDev *h, *t, *s;
  283. if((p = getconf("aoedev")) == 0)
  284. return 0;
  285. nprobe = tokenize(p, probef, nelem(probef));
  286. h = t = 0;
  287. for(i = 0; i < nprobe; i++){
  288. id = pnpprobeid(probef[i]);
  289. if(id == 0)
  290. continue;
  291. s = malloc(sizeof *s);
  292. if(s == nil)
  293. break;
  294. s->ctlr = 0;
  295. s->idno = id;
  296. s->ifc = &sdaoeifc;
  297. s->nunit = 1;
  298. if(h)
  299. t->next = s;
  300. else
  301. h = s;
  302. t = s;
  303. }
  304. return h;
  305. }
  306. static Ctlr*
  307. pnpprobe(SDev *sd)
  308. {
  309. int j;
  310. char *p;
  311. static int i;
  312. if(i > nprobe)
  313. return 0;
  314. p = probef[i++];
  315. if(strlen(p) < 2)
  316. return 0;
  317. if(p[1] == '!')
  318. p += 2;
  319. for(j = 0;; j += 200){
  320. if(j > 8000){
  321. print("#æ: pnpprobe: %s: %s\n", probef[i-1], up->errstr);
  322. return 0;
  323. }
  324. if(waserror()){
  325. tsleep(&up->sleep, return0, 0, 200);
  326. continue;
  327. }
  328. sd = aoeprobe(p, sd);
  329. poperror();
  330. break;
  331. }
  332. print("#æ: pnpprobe establishes %sin %dms\n", probef[i-1], j);
  333. return sd->ctlr;
  334. }
  335. static int
  336. aoeverify(SDunit *u)
  337. {
  338. SDev *s;
  339. Ctlr *c;
  340. s = u->dev;
  341. c = s->ctlr;
  342. if(c == nil && (s->ctlr = c = pnpprobe(s)) == nil)
  343. return 0;
  344. c->mediachange = 1;
  345. return 1;
  346. }
  347. static int
  348. aoeconnect(SDunit *u, Ctlr *c)
  349. {
  350. qlock(c);
  351. if(waserror()){
  352. qunlock(c);
  353. return -1;
  354. }
  355. aoeidentify(u->dev->ctlr, u);
  356. if(c->c)
  357. cclose(c->c);
  358. c->c = 0;
  359. uprint("%s/data", c->path);
  360. c->c = namec(up->genbuf, Aopen, ORDWR, 0);
  361. qunlock(c);
  362. poperror();
  363. return 0;
  364. }
  365. static int
  366. aoeonline(SDunit *u)
  367. {
  368. Ctlr *c;
  369. int r;
  370. c = u->dev->ctlr;
  371. r = 0;
  372. if((c->feat&Datapi) && c->mediachange){
  373. if(aoeconnect(u, c) == 0 && (r = scsionline(u)) > 0)
  374. c->mediachange = 0;
  375. return r;
  376. }
  377. if(c->mediachange){
  378. if(aoeconnect(u, c) == -1)
  379. return 0;
  380. r = 2;
  381. c->mediachange = 0;
  382. u->sectors = c->sectors;
  383. u->secsize = Aoesectsz;
  384. } else
  385. r = 1;
  386. return r;
  387. }
  388. static int
  389. aoerio(SDreq *r)
  390. {
  391. int i, count;
  392. uvlong lba;
  393. char *name;
  394. uchar *cmd;
  395. long (*rio)(Chan*, void*, long, vlong);
  396. Ctlr *c;
  397. SDunit *unit;
  398. unit = r->unit;
  399. c = unit->dev->ctlr;
  400. // if(c->feat & Datapi)
  401. // return aoeriopkt(r, d);
  402. cmd = r->cmd;
  403. name = unit->name;
  404. if(r->cmd[0] == 0x35 || r->cmd[0] == 0x91){
  405. // qlock(c);
  406. // i = flushcache();
  407. // qunlock(c);
  408. // if(i == 0)
  409. // return sdsetsense(r, SDok, 0, 0, 0);
  410. return sdsetsense(r, SDcheck, 3, 0xc, 2);
  411. }
  412. if((i = sdfakescsi(r, c->ident, sizeof c->ident)) != SDnostatus){
  413. r->status = i;
  414. return i;
  415. }
  416. switch(*cmd){
  417. case 0x88:
  418. case 0x28:
  419. rio = devtab[c->c->type]->read;
  420. break;
  421. case 0x8a:
  422. case 0x2a:
  423. rio = devtab[c->c->type]->write;
  424. break;
  425. default:
  426. print("%s: bad cmd %#.2ux\n", name, cmd[0]);
  427. r->status = SDcheck;
  428. return SDcheck;
  429. }
  430. if(r->data == nil)
  431. return SDok;
  432. if(r->clen == 16){
  433. if(cmd[2] || cmd[3])
  434. return sdsetsense(r, SDcheck, 3, 0xc, 2);
  435. lba = (uvlong)cmd[4]<<40 | (uvlong)cmd[5]<<32;
  436. lba |= cmd[6]<<24 | cmd[7]<<16 | cmd[8]<<8 | cmd[9];
  437. count = cmd[10]<<24 | cmd[11]<<16 | cmd[12]<<8 | cmd[13];
  438. }else{
  439. lba = cmd[2]<<24 | cmd[3]<<16 | cmd[4]<<8 | cmd[5];
  440. count = cmd[7]<<8 | cmd[8];
  441. }
  442. count *= Aoesectsz;
  443. if(r->dlen < count)
  444. count = r->dlen & ~0x1ff;
  445. if(waserror()){
  446. if(strcmp(up->errstr, Echange) == 0 ||
  447. strcmp(up->errstr, Enotup) == 0)
  448. unit->sectors = 0;
  449. nexterror();
  450. }
  451. r->rlen = rio(c->c, r->data, count, Aoesectsz * lba);
  452. poperror();
  453. r->status = SDok;
  454. return SDok;
  455. }
  456. static char *smarttab[] = {
  457. "unset",
  458. "error",
  459. "threshold exceeded",
  460. "normal"
  461. };
  462. static char *
  463. pflag(char *s, char *e, uchar f)
  464. {
  465. uchar i, m;
  466. for(i = 0; i < 8; i++){
  467. m = 1 << i;
  468. if(f & m)
  469. s = seprint(s, e, "%s ", flagname[i]);
  470. }
  471. return seprint(s, e, "\n");
  472. }
  473. static int
  474. aoerctl(SDunit *u, char *p, int l)
  475. {
  476. Ctlr *c;
  477. char *e, *op;
  478. if((c = u->dev->ctlr) == nil)
  479. return 0;
  480. e = p+l;
  481. op = p;
  482. p = seprint(p, e, "model\t%s\n", c->model);
  483. p = seprint(p, e, "serial\t%s\n", c->serial);
  484. p = seprint(p, e, "firm %s\n", c->firmware);
  485. if(c->smartrs == 0xff)
  486. p = seprint(p, e, "smart\tenable error\n");
  487. else if(c->smartrs == 0)
  488. p = seprint(p, e, "smart\tdisabled\n");
  489. else
  490. p = seprint(p, e, "smart\t%s\n", smarttab[c->smart]);
  491. p = seprint(p, e, "flag ");
  492. p = pflag(p, e, c->feat);
  493. p = seprint(p, e, "geometry %llud %d\n", c->sectors, Aoesectsz);
  494. return p-op;
  495. }
  496. static int
  497. aoewctl(SDunit *, Cmdbuf *cmd)
  498. {
  499. cmderror(cmd, Ebadarg);
  500. return 0;
  501. }
  502. static SDev*
  503. aoeprobew(DevConf *c)
  504. {
  505. char *p;
  506. p = strchr(c->type, '/');
  507. if(p == nil || strlen(p) > Maxpath - 11)
  508. error(Ebadarg);
  509. if(p[1] == '#')
  510. p++; /* hack */
  511. if(ctlrlookup(p))
  512. error(Einuse);
  513. return aoeprobe(p, 0);
  514. }
  515. static void
  516. aoeclear(SDev *s)
  517. {
  518. delctlr((Ctlr *)s->ctlr);
  519. }
  520. static char*
  521. aoertopctl(SDev *s, char *p, char *e)
  522. {
  523. Ctlr *c;
  524. c = s->ctlr;
  525. return seprint(p, e, "%s aoe %s\n", s->name, c->path);
  526. }
  527. static int
  528. aoewtopctl(SDev *, Cmdbuf *cmd)
  529. {
  530. switch(cmd->nf){
  531. default:
  532. cmderror(cmd, Ebadarg);
  533. }
  534. return 0;
  535. }
  536. SDifc sdaoeifc = {
  537. "aoe",
  538. aoepnp,
  539. nil, /* legacy */
  540. nil, /* enable */
  541. nil, /* disable */
  542. aoeverify,
  543. aoeonline,
  544. aoerio,
  545. aoerctl,
  546. aoewctl,
  547. scsibio,
  548. aoeprobew, /* probe */
  549. aoeclear, /* clear */
  550. aoertopctl,
  551. aoewtopctl,
  552. };