ses.c revision 21fab1d0595eacf781705ec3509012a28f298245
19927c68864e9c39cc317b4f559309ba29e642168James Bottomley/* 29927c68864e9c39cc317b4f559309ba29e642168James Bottomley * SCSI Enclosure Services 39927c68864e9c39cc317b4f559309ba29e642168James Bottomley * 49927c68864e9c39cc317b4f559309ba29e642168James Bottomley * Copyright (C) 2008 James Bottomley <James.Bottomley@HansenPartnership.com> 59927c68864e9c39cc317b4f559309ba29e642168James Bottomley * 69927c68864e9c39cc317b4f559309ba29e642168James Bottomley**----------------------------------------------------------------------------- 79927c68864e9c39cc317b4f559309ba29e642168James Bottomley** 89927c68864e9c39cc317b4f559309ba29e642168James Bottomley** This program is free software; you can redistribute it and/or 99927c68864e9c39cc317b4f559309ba29e642168James Bottomley** modify it under the terms of the GNU General Public License 109927c68864e9c39cc317b4f559309ba29e642168James Bottomley** version 2 as published by the Free Software Foundation. 119927c68864e9c39cc317b4f559309ba29e642168James Bottomley** 129927c68864e9c39cc317b4f559309ba29e642168James Bottomley** This program is distributed in the hope that it will be useful, 139927c68864e9c39cc317b4f559309ba29e642168James Bottomley** but WITHOUT ANY WARRANTY; without even the implied warranty of 149927c68864e9c39cc317b4f559309ba29e642168James Bottomley** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 159927c68864e9c39cc317b4f559309ba29e642168James Bottomley** GNU General Public License for more details. 169927c68864e9c39cc317b4f559309ba29e642168James Bottomley** 179927c68864e9c39cc317b4f559309ba29e642168James Bottomley** You should have received a copy of the GNU General Public License 189927c68864e9c39cc317b4f559309ba29e642168James Bottomley** along with this program; if not, write to the Free Software 199927c68864e9c39cc317b4f559309ba29e642168James Bottomley** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 209927c68864e9c39cc317b4f559309ba29e642168James Bottomley** 219927c68864e9c39cc317b4f559309ba29e642168James Bottomley**----------------------------------------------------------------------------- 229927c68864e9c39cc317b4f559309ba29e642168James Bottomley*/ 239927c68864e9c39cc317b4f559309ba29e642168James Bottomley 249927c68864e9c39cc317b4f559309ba29e642168James Bottomley#include <linux/module.h> 259927c68864e9c39cc317b4f559309ba29e642168James Bottomley#include <linux/kernel.h> 269927c68864e9c39cc317b4f559309ba29e642168James Bottomley#include <linux/enclosure.h> 279927c68864e9c39cc317b4f559309ba29e642168James Bottomley 289927c68864e9c39cc317b4f559309ba29e642168James Bottomley#include <scsi/scsi.h> 299927c68864e9c39cc317b4f559309ba29e642168James Bottomley#include <scsi/scsi_cmnd.h> 309927c68864e9c39cc317b4f559309ba29e642168James Bottomley#include <scsi/scsi_dbg.h> 319927c68864e9c39cc317b4f559309ba29e642168James Bottomley#include <scsi/scsi_device.h> 329927c68864e9c39cc317b4f559309ba29e642168James Bottomley#include <scsi/scsi_driver.h> 339927c68864e9c39cc317b4f559309ba29e642168James Bottomley#include <scsi/scsi_host.h> 349927c68864e9c39cc317b4f559309ba29e642168James Bottomley 359927c68864e9c39cc317b4f559309ba29e642168James Bottomleystruct ses_device { 36691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu unsigned char *page1; 37691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu unsigned char *page2; 38691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu unsigned char *page10; 399927c68864e9c39cc317b4f559309ba29e642168James Bottomley short page1_len; 409927c68864e9c39cc317b4f559309ba29e642168James Bottomley short page2_len; 419927c68864e9c39cc317b4f559309ba29e642168James Bottomley short page10_len; 429927c68864e9c39cc317b4f559309ba29e642168James Bottomley}; 439927c68864e9c39cc317b4f559309ba29e642168James Bottomley 449927c68864e9c39cc317b4f559309ba29e642168James Bottomleystruct ses_component { 459927c68864e9c39cc317b4f559309ba29e642168James Bottomley u64 addr; 469927c68864e9c39cc317b4f559309ba29e642168James Bottomley unsigned char *desc; 479927c68864e9c39cc317b4f559309ba29e642168James Bottomley}; 489927c68864e9c39cc317b4f559309ba29e642168James Bottomley 499927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic int ses_probe(struct device *dev) 509927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 519927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct scsi_device *sdev = to_scsi_device(dev); 529927c68864e9c39cc317b4f559309ba29e642168James Bottomley int err = -ENODEV; 539927c68864e9c39cc317b4f559309ba29e642168James Bottomley 549927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (sdev->type != TYPE_ENCLOSURE) 559927c68864e9c39cc317b4f559309ba29e642168James Bottomley goto out; 569927c68864e9c39cc317b4f559309ba29e642168James Bottomley 579927c68864e9c39cc317b4f559309ba29e642168James Bottomley err = 0; 589927c68864e9c39cc317b4f559309ba29e642168James Bottomley sdev_printk(KERN_NOTICE, sdev, "Attached Enclosure device\n"); 599927c68864e9c39cc317b4f559309ba29e642168James Bottomley 609927c68864e9c39cc317b4f559309ba29e642168James Bottomley out: 619927c68864e9c39cc317b4f559309ba29e642168James Bottomley return err; 629927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 639927c68864e9c39cc317b4f559309ba29e642168James Bottomley 64c95e62ce8905aab62fed224eaaa9b8558a0ef652Matthew Wilcox#define SES_TIMEOUT (30 * HZ) 659927c68864e9c39cc317b4f559309ba29e642168James Bottomley#define SES_RETRIES 3 669927c68864e9c39cc317b4f559309ba29e642168James Bottomley 679927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic int ses_recv_diag(struct scsi_device *sdev, int page_code, 689927c68864e9c39cc317b4f559309ba29e642168James Bottomley void *buf, int bufflen) 699927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 70691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu unsigned char cmd[] = { 719927c68864e9c39cc317b4f559309ba29e642168James Bottomley RECEIVE_DIAGNOSTIC, 729927c68864e9c39cc317b4f559309ba29e642168James Bottomley 1, /* Set PCV bit */ 739927c68864e9c39cc317b4f559309ba29e642168James Bottomley page_code, 749927c68864e9c39cc317b4f559309ba29e642168James Bottomley bufflen >> 8, 759927c68864e9c39cc317b4f559309ba29e642168James Bottomley bufflen & 0xff, 769927c68864e9c39cc317b4f559309ba29e642168James Bottomley 0 779927c68864e9c39cc317b4f559309ba29e642168James Bottomley }; 789927c68864e9c39cc317b4f559309ba29e642168James Bottomley 799927c68864e9c39cc317b4f559309ba29e642168James Bottomley return scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buf, bufflen, 80f4f4e47e4af6b02dd1c425b931c65d0165356e33FUJITA Tomonori NULL, SES_TIMEOUT, SES_RETRIES, NULL); 819927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 829927c68864e9c39cc317b4f559309ba29e642168James Bottomley 839927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic int ses_send_diag(struct scsi_device *sdev, int page_code, 849927c68864e9c39cc317b4f559309ba29e642168James Bottomley void *buf, int bufflen) 859927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 869927c68864e9c39cc317b4f559309ba29e642168James Bottomley u32 result; 879927c68864e9c39cc317b4f559309ba29e642168James Bottomley 88691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu unsigned char cmd[] = { 899927c68864e9c39cc317b4f559309ba29e642168James Bottomley SEND_DIAGNOSTIC, 909927c68864e9c39cc317b4f559309ba29e642168James Bottomley 0x10, /* Set PF bit */ 919927c68864e9c39cc317b4f559309ba29e642168James Bottomley 0, 929927c68864e9c39cc317b4f559309ba29e642168James Bottomley bufflen >> 8, 939927c68864e9c39cc317b4f559309ba29e642168James Bottomley bufflen & 0xff, 949927c68864e9c39cc317b4f559309ba29e642168James Bottomley 0 959927c68864e9c39cc317b4f559309ba29e642168James Bottomley }; 969927c68864e9c39cc317b4f559309ba29e642168James Bottomley 979927c68864e9c39cc317b4f559309ba29e642168James Bottomley result = scsi_execute_req(sdev, cmd, DMA_TO_DEVICE, buf, bufflen, 98f4f4e47e4af6b02dd1c425b931c65d0165356e33FUJITA Tomonori NULL, SES_TIMEOUT, SES_RETRIES, NULL); 999927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (result) 1009927c68864e9c39cc317b4f559309ba29e642168James Bottomley sdev_printk(KERN_ERR, sdev, "SEND DIAGNOSTIC result: %8x\n", 1019927c68864e9c39cc317b4f559309ba29e642168James Bottomley result); 1029927c68864e9c39cc317b4f559309ba29e642168James Bottomley return result; 1039927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 1049927c68864e9c39cc317b4f559309ba29e642168James Bottomley 1059927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic int ses_set_page2_descriptor(struct enclosure_device *edev, 1069927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct enclosure_component *ecomp, 107691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu unsigned char *desc) 1089927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 1099927c68864e9c39cc317b4f559309ba29e642168James Bottomley int i, j, count = 0, descriptor = ecomp->number; 110ee959b00c335d7780136c5abda37809191fe52c3Tony Jones struct scsi_device *sdev = to_scsi_device(edev->edev.parent); 1119927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct ses_device *ses_dev = edev->scratch; 112691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu unsigned char *type_ptr = ses_dev->page1 + 12 + ses_dev->page1[11]; 113691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu unsigned char *desc_ptr = ses_dev->page2 + 8; 1149927c68864e9c39cc317b4f559309ba29e642168James Bottomley 1159927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* Clear everything */ 1169927c68864e9c39cc317b4f559309ba29e642168James Bottomley memset(desc_ptr, 0, ses_dev->page2_len - 8); 1179927c68864e9c39cc317b4f559309ba29e642168James Bottomley for (i = 0; i < ses_dev->page1[10]; i++, type_ptr += 4) { 1189927c68864e9c39cc317b4f559309ba29e642168James Bottomley for (j = 0; j < type_ptr[1]; j++) { 1199927c68864e9c39cc317b4f559309ba29e642168James Bottomley desc_ptr += 4; 1209927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (type_ptr[0] != ENCLOSURE_COMPONENT_DEVICE && 1219927c68864e9c39cc317b4f559309ba29e642168James Bottomley type_ptr[0] != ENCLOSURE_COMPONENT_ARRAY_DEVICE) 1229927c68864e9c39cc317b4f559309ba29e642168James Bottomley continue; 1239927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (count++ == descriptor) { 1249927c68864e9c39cc317b4f559309ba29e642168James Bottomley memcpy(desc_ptr, desc, 4); 1259927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* set select */ 1269927c68864e9c39cc317b4f559309ba29e642168James Bottomley desc_ptr[0] |= 0x80; 1279927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* clear reserved, just in case */ 1289927c68864e9c39cc317b4f559309ba29e642168James Bottomley desc_ptr[0] &= 0xf0; 1299927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 1309927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 1319927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 1329927c68864e9c39cc317b4f559309ba29e642168James Bottomley 1339927c68864e9c39cc317b4f559309ba29e642168James Bottomley return ses_send_diag(sdev, 2, ses_dev->page2, ses_dev->page2_len); 1349927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 1359927c68864e9c39cc317b4f559309ba29e642168James Bottomley 136691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lustatic unsigned char *ses_get_page2_descriptor(struct enclosure_device *edev, 1379927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct enclosure_component *ecomp) 1389927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 1399927c68864e9c39cc317b4f559309ba29e642168James Bottomley int i, j, count = 0, descriptor = ecomp->number; 140ee959b00c335d7780136c5abda37809191fe52c3Tony Jones struct scsi_device *sdev = to_scsi_device(edev->edev.parent); 1419927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct ses_device *ses_dev = edev->scratch; 142691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu unsigned char *type_ptr = ses_dev->page1 + 12 + ses_dev->page1[11]; 143691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu unsigned char *desc_ptr = ses_dev->page2 + 8; 1449927c68864e9c39cc317b4f559309ba29e642168James Bottomley 1459927c68864e9c39cc317b4f559309ba29e642168James Bottomley ses_recv_diag(sdev, 2, ses_dev->page2, ses_dev->page2_len); 1469927c68864e9c39cc317b4f559309ba29e642168James Bottomley 1479927c68864e9c39cc317b4f559309ba29e642168James Bottomley for (i = 0; i < ses_dev->page1[10]; i++, type_ptr += 4) { 1489927c68864e9c39cc317b4f559309ba29e642168James Bottomley for (j = 0; j < type_ptr[1]; j++) { 1499927c68864e9c39cc317b4f559309ba29e642168James Bottomley desc_ptr += 4; 1509927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (type_ptr[0] != ENCLOSURE_COMPONENT_DEVICE && 1519927c68864e9c39cc317b4f559309ba29e642168James Bottomley type_ptr[0] != ENCLOSURE_COMPONENT_ARRAY_DEVICE) 1529927c68864e9c39cc317b4f559309ba29e642168James Bottomley continue; 1539927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (count++ == descriptor) 1549927c68864e9c39cc317b4f559309ba29e642168James Bottomley return desc_ptr; 1559927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 1569927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 1579927c68864e9c39cc317b4f559309ba29e642168James Bottomley return NULL; 1589927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 1599927c68864e9c39cc317b4f559309ba29e642168James Bottomley 1609927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic void ses_get_fault(struct enclosure_device *edev, 1619927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct enclosure_component *ecomp) 1629927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 163691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu unsigned char *desc; 1649927c68864e9c39cc317b4f559309ba29e642168James Bottomley 1659927c68864e9c39cc317b4f559309ba29e642168James Bottomley desc = ses_get_page2_descriptor(edev, ecomp); 166691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu if (desc) 167691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu ecomp->fault = (desc[3] & 0x60) >> 4; 1689927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 1699927c68864e9c39cc317b4f559309ba29e642168James Bottomley 1709927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic int ses_set_fault(struct enclosure_device *edev, 1719927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct enclosure_component *ecomp, 1729927c68864e9c39cc317b4f559309ba29e642168James Bottomley enum enclosure_component_setting val) 1739927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 174691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu unsigned char desc[4] = {0 }; 1759927c68864e9c39cc317b4f559309ba29e642168James Bottomley 1769927c68864e9c39cc317b4f559309ba29e642168James Bottomley switch (val) { 1779927c68864e9c39cc317b4f559309ba29e642168James Bottomley case ENCLOSURE_SETTING_DISABLED: 1789927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* zero is disabled */ 1799927c68864e9c39cc317b4f559309ba29e642168James Bottomley break; 1809927c68864e9c39cc317b4f559309ba29e642168James Bottomley case ENCLOSURE_SETTING_ENABLED: 1819927c68864e9c39cc317b4f559309ba29e642168James Bottomley desc[2] = 0x02; 1829927c68864e9c39cc317b4f559309ba29e642168James Bottomley break; 1839927c68864e9c39cc317b4f559309ba29e642168James Bottomley default: 1849927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* SES doesn't do the SGPIO blink settings */ 1859927c68864e9c39cc317b4f559309ba29e642168James Bottomley return -EINVAL; 1869927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 1879927c68864e9c39cc317b4f559309ba29e642168James Bottomley 1889927c68864e9c39cc317b4f559309ba29e642168James Bottomley return ses_set_page2_descriptor(edev, ecomp, desc); 1899927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 1909927c68864e9c39cc317b4f559309ba29e642168James Bottomley 1919927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic void ses_get_status(struct enclosure_device *edev, 1929927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct enclosure_component *ecomp) 1939927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 194691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu unsigned char *desc; 1959927c68864e9c39cc317b4f559309ba29e642168James Bottomley 1969927c68864e9c39cc317b4f559309ba29e642168James Bottomley desc = ses_get_page2_descriptor(edev, ecomp); 197691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu if (desc) 198691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu ecomp->status = (desc[0] & 0x0f); 1999927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 2009927c68864e9c39cc317b4f559309ba29e642168James Bottomley 2019927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic void ses_get_locate(struct enclosure_device *edev, 2029927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct enclosure_component *ecomp) 2039927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 204691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu unsigned char *desc; 2059927c68864e9c39cc317b4f559309ba29e642168James Bottomley 2069927c68864e9c39cc317b4f559309ba29e642168James Bottomley desc = ses_get_page2_descriptor(edev, ecomp); 207691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu if (desc) 208691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu ecomp->locate = (desc[2] & 0x02) ? 1 : 0; 2099927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 2109927c68864e9c39cc317b4f559309ba29e642168James Bottomley 2119927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic int ses_set_locate(struct enclosure_device *edev, 2129927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct enclosure_component *ecomp, 2139927c68864e9c39cc317b4f559309ba29e642168James Bottomley enum enclosure_component_setting val) 2149927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 215691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu unsigned char desc[4] = {0 }; 2169927c68864e9c39cc317b4f559309ba29e642168James Bottomley 2179927c68864e9c39cc317b4f559309ba29e642168James Bottomley switch (val) { 2189927c68864e9c39cc317b4f559309ba29e642168James Bottomley case ENCLOSURE_SETTING_DISABLED: 2199927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* zero is disabled */ 2209927c68864e9c39cc317b4f559309ba29e642168James Bottomley break; 2219927c68864e9c39cc317b4f559309ba29e642168James Bottomley case ENCLOSURE_SETTING_ENABLED: 2229927c68864e9c39cc317b4f559309ba29e642168James Bottomley desc[2] = 0x02; 2239927c68864e9c39cc317b4f559309ba29e642168James Bottomley break; 2249927c68864e9c39cc317b4f559309ba29e642168James Bottomley default: 2259927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* SES doesn't do the SGPIO blink settings */ 2269927c68864e9c39cc317b4f559309ba29e642168James Bottomley return -EINVAL; 2279927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 2289927c68864e9c39cc317b4f559309ba29e642168James Bottomley return ses_set_page2_descriptor(edev, ecomp, desc); 2299927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 2309927c68864e9c39cc317b4f559309ba29e642168James Bottomley 2319927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic int ses_set_active(struct enclosure_device *edev, 2329927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct enclosure_component *ecomp, 2339927c68864e9c39cc317b4f559309ba29e642168James Bottomley enum enclosure_component_setting val) 2349927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 235691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu unsigned char desc[4] = {0 }; 2369927c68864e9c39cc317b4f559309ba29e642168James Bottomley 2379927c68864e9c39cc317b4f559309ba29e642168James Bottomley switch (val) { 2389927c68864e9c39cc317b4f559309ba29e642168James Bottomley case ENCLOSURE_SETTING_DISABLED: 2399927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* zero is disabled */ 2409927c68864e9c39cc317b4f559309ba29e642168James Bottomley ecomp->active = 0; 2419927c68864e9c39cc317b4f559309ba29e642168James Bottomley break; 2429927c68864e9c39cc317b4f559309ba29e642168James Bottomley case ENCLOSURE_SETTING_ENABLED: 2439927c68864e9c39cc317b4f559309ba29e642168James Bottomley desc[2] = 0x80; 2449927c68864e9c39cc317b4f559309ba29e642168James Bottomley ecomp->active = 1; 2459927c68864e9c39cc317b4f559309ba29e642168James Bottomley break; 2469927c68864e9c39cc317b4f559309ba29e642168James Bottomley default: 2479927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* SES doesn't do the SGPIO blink settings */ 2489927c68864e9c39cc317b4f559309ba29e642168James Bottomley return -EINVAL; 2499927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 2509927c68864e9c39cc317b4f559309ba29e642168James Bottomley return ses_set_page2_descriptor(edev, ecomp, desc); 2519927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 2529927c68864e9c39cc317b4f559309ba29e642168James Bottomley 2539927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic struct enclosure_component_callbacks ses_enclosure_callbacks = { 2549927c68864e9c39cc317b4f559309ba29e642168James Bottomley .get_fault = ses_get_fault, 2559927c68864e9c39cc317b4f559309ba29e642168James Bottomley .set_fault = ses_set_fault, 2569927c68864e9c39cc317b4f559309ba29e642168James Bottomley .get_status = ses_get_status, 2579927c68864e9c39cc317b4f559309ba29e642168James Bottomley .get_locate = ses_get_locate, 2589927c68864e9c39cc317b4f559309ba29e642168James Bottomley .set_locate = ses_set_locate, 2599927c68864e9c39cc317b4f559309ba29e642168James Bottomley .set_active = ses_set_active, 2609927c68864e9c39cc317b4f559309ba29e642168James Bottomley}; 2619927c68864e9c39cc317b4f559309ba29e642168James Bottomley 2629927c68864e9c39cc317b4f559309ba29e642168James Bottomleystruct ses_host_edev { 2639927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct Scsi_Host *shost; 2649927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct enclosure_device *edev; 2659927c68864e9c39cc317b4f559309ba29e642168James Bottomley}; 2669927c68864e9c39cc317b4f559309ba29e642168James Bottomley 267e0aae1a53133f0d7833c8f358a0ccc7055fc5b28Adrian Bunk#if 0 2689927c68864e9c39cc317b4f559309ba29e642168James Bottomleyint ses_match_host(struct enclosure_device *edev, void *data) 2699927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 2709927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct ses_host_edev *sed = data; 2719927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct scsi_device *sdev; 2729927c68864e9c39cc317b4f559309ba29e642168James Bottomley 273ee959b00c335d7780136c5abda37809191fe52c3Tony Jones if (!scsi_is_sdev_device(edev->edev.parent)) 2749927c68864e9c39cc317b4f559309ba29e642168James Bottomley return 0; 2759927c68864e9c39cc317b4f559309ba29e642168James Bottomley 276ee959b00c335d7780136c5abda37809191fe52c3Tony Jones sdev = to_scsi_device(edev->edev.parent); 2779927c68864e9c39cc317b4f559309ba29e642168James Bottomley 2789927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (sdev->host != sed->shost) 2799927c68864e9c39cc317b4f559309ba29e642168James Bottomley return 0; 2809927c68864e9c39cc317b4f559309ba29e642168James Bottomley 2819927c68864e9c39cc317b4f559309ba29e642168James Bottomley sed->edev = edev; 2829927c68864e9c39cc317b4f559309ba29e642168James Bottomley return 1; 2839927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 284e0aae1a53133f0d7833c8f358a0ccc7055fc5b28Adrian Bunk#endif /* 0 */ 2859927c68864e9c39cc317b4f559309ba29e642168James Bottomley 2869927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic void ses_process_descriptor(struct enclosure_component *ecomp, 2879927c68864e9c39cc317b4f559309ba29e642168James Bottomley unsigned char *desc) 2889927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 2899927c68864e9c39cc317b4f559309ba29e642168James Bottomley int eip = desc[0] & 0x10; 2909927c68864e9c39cc317b4f559309ba29e642168James Bottomley int invalid = desc[0] & 0x80; 2919927c68864e9c39cc317b4f559309ba29e642168James Bottomley enum scsi_protocol proto = desc[0] & 0x0f; 2929927c68864e9c39cc317b4f559309ba29e642168James Bottomley u64 addr = 0; 2939927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct ses_component *scomp = ecomp->scratch; 2949927c68864e9c39cc317b4f559309ba29e642168James Bottomley unsigned char *d; 2959927c68864e9c39cc317b4f559309ba29e642168James Bottomley 2969927c68864e9c39cc317b4f559309ba29e642168James Bottomley scomp->desc = desc; 2979927c68864e9c39cc317b4f559309ba29e642168James Bottomley 2989927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (invalid) 2999927c68864e9c39cc317b4f559309ba29e642168James Bottomley return; 3009927c68864e9c39cc317b4f559309ba29e642168James Bottomley 3019927c68864e9c39cc317b4f559309ba29e642168James Bottomley switch (proto) { 3029927c68864e9c39cc317b4f559309ba29e642168James Bottomley case SCSI_PROTOCOL_SAS: 3039927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (eip) 3049927c68864e9c39cc317b4f559309ba29e642168James Bottomley d = desc + 8; 3059927c68864e9c39cc317b4f559309ba29e642168James Bottomley else 3069927c68864e9c39cc317b4f559309ba29e642168James Bottomley d = desc + 4; 3079927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* only take the phy0 addr */ 3089927c68864e9c39cc317b4f559309ba29e642168James Bottomley addr = (u64)d[12] << 56 | 3099927c68864e9c39cc317b4f559309ba29e642168James Bottomley (u64)d[13] << 48 | 3109927c68864e9c39cc317b4f559309ba29e642168James Bottomley (u64)d[14] << 40 | 3119927c68864e9c39cc317b4f559309ba29e642168James Bottomley (u64)d[15] << 32 | 3129927c68864e9c39cc317b4f559309ba29e642168James Bottomley (u64)d[16] << 24 | 3139927c68864e9c39cc317b4f559309ba29e642168James Bottomley (u64)d[17] << 16 | 3149927c68864e9c39cc317b4f559309ba29e642168James Bottomley (u64)d[18] << 8 | 3159927c68864e9c39cc317b4f559309ba29e642168James Bottomley (u64)d[19]; 3169927c68864e9c39cc317b4f559309ba29e642168James Bottomley break; 3179927c68864e9c39cc317b4f559309ba29e642168James Bottomley default: 3189927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* FIXME: Need to add more protocols than just SAS */ 3199927c68864e9c39cc317b4f559309ba29e642168James Bottomley break; 3209927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 3219927c68864e9c39cc317b4f559309ba29e642168James Bottomley scomp->addr = addr; 3229927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 3239927c68864e9c39cc317b4f559309ba29e642168James Bottomley 3249927c68864e9c39cc317b4f559309ba29e642168James Bottomleystruct efd { 3259927c68864e9c39cc317b4f559309ba29e642168James Bottomley u64 addr; 3269927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct device *dev; 3279927c68864e9c39cc317b4f559309ba29e642168James Bottomley}; 3289927c68864e9c39cc317b4f559309ba29e642168James Bottomley 3299927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic int ses_enclosure_find_by_addr(struct enclosure_device *edev, 3309927c68864e9c39cc317b4f559309ba29e642168James Bottomley void *data) 3319927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 3329927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct efd *efd = data; 3339927c68864e9c39cc317b4f559309ba29e642168James Bottomley int i; 3349927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct ses_component *scomp; 3359927c68864e9c39cc317b4f559309ba29e642168James Bottomley 3369927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (!edev->component[0].scratch) 3379927c68864e9c39cc317b4f559309ba29e642168James Bottomley return 0; 3389927c68864e9c39cc317b4f559309ba29e642168James Bottomley 3399927c68864e9c39cc317b4f559309ba29e642168James Bottomley for (i = 0; i < edev->components; i++) { 3409927c68864e9c39cc317b4f559309ba29e642168James Bottomley scomp = edev->component[i].scratch; 3419927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (scomp->addr != efd->addr) 3429927c68864e9c39cc317b4f559309ba29e642168James Bottomley continue; 3439927c68864e9c39cc317b4f559309ba29e642168James Bottomley 3449927c68864e9c39cc317b4f559309ba29e642168James Bottomley enclosure_add_device(edev, i, efd->dev); 3459927c68864e9c39cc317b4f559309ba29e642168James Bottomley return 1; 3469927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 3479927c68864e9c39cc317b4f559309ba29e642168James Bottomley return 0; 3489927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 3499927c68864e9c39cc317b4f559309ba29e642168James Bottomley 35021fab1d0595eacf781705ec3509012a28f298245James Bottomley#define INIT_ALLOC_SIZE 32 35121fab1d0595eacf781705ec3509012a28f298245James Bottomley 35221fab1d0595eacf781705ec3509012a28f298245James Bottomleystatic void ses_enclosure_data_process(struct enclosure_device *edev, 35321fab1d0595eacf781705ec3509012a28f298245James Bottomley struct scsi_device *sdev, 35421fab1d0595eacf781705ec3509012a28f298245James Bottomley int create) 35521fab1d0595eacf781705ec3509012a28f298245James Bottomley{ 35621fab1d0595eacf781705ec3509012a28f298245James Bottomley u32 result; 35721fab1d0595eacf781705ec3509012a28f298245James Bottomley unsigned char *buf = NULL, *type_ptr, *desc_ptr, *addl_desc_ptr = NULL; 35821fab1d0595eacf781705ec3509012a28f298245James Bottomley int i, j, page7_len, len, components; 35921fab1d0595eacf781705ec3509012a28f298245James Bottomley struct ses_device *ses_dev = edev->scratch; 36021fab1d0595eacf781705ec3509012a28f298245James Bottomley int types = ses_dev->page1[10]; 36121fab1d0595eacf781705ec3509012a28f298245James Bottomley unsigned char *hdr_buf = kzalloc(INIT_ALLOC_SIZE, GFP_KERNEL); 36221fab1d0595eacf781705ec3509012a28f298245James Bottomley 36321fab1d0595eacf781705ec3509012a28f298245James Bottomley if (!hdr_buf) 36421fab1d0595eacf781705ec3509012a28f298245James Bottomley goto simple_populate; 36521fab1d0595eacf781705ec3509012a28f298245James Bottomley 36621fab1d0595eacf781705ec3509012a28f298245James Bottomley /* re-read page 10 */ 36721fab1d0595eacf781705ec3509012a28f298245James Bottomley if (ses_dev->page10) 36821fab1d0595eacf781705ec3509012a28f298245James Bottomley ses_recv_diag(sdev, 10, ses_dev->page10, ses_dev->page10_len); 36921fab1d0595eacf781705ec3509012a28f298245James Bottomley /* Page 7 for the descriptors is optional */ 37021fab1d0595eacf781705ec3509012a28f298245James Bottomley result = ses_recv_diag(sdev, 7, hdr_buf, INIT_ALLOC_SIZE); 37121fab1d0595eacf781705ec3509012a28f298245James Bottomley if (result) 37221fab1d0595eacf781705ec3509012a28f298245James Bottomley goto simple_populate; 37321fab1d0595eacf781705ec3509012a28f298245James Bottomley 37421fab1d0595eacf781705ec3509012a28f298245James Bottomley page7_len = len = (hdr_buf[2] << 8) + hdr_buf[3] + 4; 37521fab1d0595eacf781705ec3509012a28f298245James Bottomley /* add 1 for trailing '\0' we'll use */ 37621fab1d0595eacf781705ec3509012a28f298245James Bottomley buf = kzalloc(len + 1, GFP_KERNEL); 37721fab1d0595eacf781705ec3509012a28f298245James Bottomley if (!buf) 37821fab1d0595eacf781705ec3509012a28f298245James Bottomley goto simple_populate; 37921fab1d0595eacf781705ec3509012a28f298245James Bottomley result = ses_recv_diag(sdev, 7, buf, len); 38021fab1d0595eacf781705ec3509012a28f298245James Bottomley if (result) { 38121fab1d0595eacf781705ec3509012a28f298245James Bottomley simple_populate: 38221fab1d0595eacf781705ec3509012a28f298245James Bottomley kfree(buf); 38321fab1d0595eacf781705ec3509012a28f298245James Bottomley buf = NULL; 38421fab1d0595eacf781705ec3509012a28f298245James Bottomley desc_ptr = NULL; 38521fab1d0595eacf781705ec3509012a28f298245James Bottomley len = 0; 38621fab1d0595eacf781705ec3509012a28f298245James Bottomley page7_len = 0; 38721fab1d0595eacf781705ec3509012a28f298245James Bottomley } else { 38821fab1d0595eacf781705ec3509012a28f298245James Bottomley desc_ptr = buf + 8; 38921fab1d0595eacf781705ec3509012a28f298245James Bottomley len = (desc_ptr[2] << 8) + desc_ptr[3]; 39021fab1d0595eacf781705ec3509012a28f298245James Bottomley /* skip past overall descriptor */ 39121fab1d0595eacf781705ec3509012a28f298245James Bottomley desc_ptr += len + 4; 39221fab1d0595eacf781705ec3509012a28f298245James Bottomley if (ses_dev->page10) 39321fab1d0595eacf781705ec3509012a28f298245James Bottomley addl_desc_ptr = ses_dev->page10 + 8; 39421fab1d0595eacf781705ec3509012a28f298245James Bottomley } 39521fab1d0595eacf781705ec3509012a28f298245James Bottomley type_ptr = ses_dev->page1 + 12 + ses_dev->page1[11]; 39621fab1d0595eacf781705ec3509012a28f298245James Bottomley components = 0; 39721fab1d0595eacf781705ec3509012a28f298245James Bottomley for (i = 0; i < types; i++, type_ptr += 4) { 39821fab1d0595eacf781705ec3509012a28f298245James Bottomley for (j = 0; j < type_ptr[1]; j++) { 39921fab1d0595eacf781705ec3509012a28f298245James Bottomley char *name = NULL; 40021fab1d0595eacf781705ec3509012a28f298245James Bottomley struct enclosure_component *ecomp; 40121fab1d0595eacf781705ec3509012a28f298245James Bottomley 40221fab1d0595eacf781705ec3509012a28f298245James Bottomley if (desc_ptr) { 40321fab1d0595eacf781705ec3509012a28f298245James Bottomley if (desc_ptr >= buf + page7_len) { 40421fab1d0595eacf781705ec3509012a28f298245James Bottomley desc_ptr = NULL; 40521fab1d0595eacf781705ec3509012a28f298245James Bottomley } else { 40621fab1d0595eacf781705ec3509012a28f298245James Bottomley len = (desc_ptr[2] << 8) + desc_ptr[3]; 40721fab1d0595eacf781705ec3509012a28f298245James Bottomley desc_ptr += 4; 40821fab1d0595eacf781705ec3509012a28f298245James Bottomley /* Add trailing zero - pushes into 40921fab1d0595eacf781705ec3509012a28f298245James Bottomley * reserved space */ 41021fab1d0595eacf781705ec3509012a28f298245James Bottomley desc_ptr[len] = '\0'; 41121fab1d0595eacf781705ec3509012a28f298245James Bottomley name = desc_ptr; 41221fab1d0595eacf781705ec3509012a28f298245James Bottomley } 41321fab1d0595eacf781705ec3509012a28f298245James Bottomley } 41421fab1d0595eacf781705ec3509012a28f298245James Bottomley if (type_ptr[0] == ENCLOSURE_COMPONENT_DEVICE || 41521fab1d0595eacf781705ec3509012a28f298245James Bottomley type_ptr[0] == ENCLOSURE_COMPONENT_ARRAY_DEVICE) { 41621fab1d0595eacf781705ec3509012a28f298245James Bottomley 41721fab1d0595eacf781705ec3509012a28f298245James Bottomley if (create) 41821fab1d0595eacf781705ec3509012a28f298245James Bottomley ecomp = enclosure_component_register(edev, 41921fab1d0595eacf781705ec3509012a28f298245James Bottomley components++, 42021fab1d0595eacf781705ec3509012a28f298245James Bottomley type_ptr[0], 42121fab1d0595eacf781705ec3509012a28f298245James Bottomley name); 42221fab1d0595eacf781705ec3509012a28f298245James Bottomley else 42321fab1d0595eacf781705ec3509012a28f298245James Bottomley ecomp = &edev->component[components++]; 42421fab1d0595eacf781705ec3509012a28f298245James Bottomley 42521fab1d0595eacf781705ec3509012a28f298245James Bottomley if (!IS_ERR(ecomp) && addl_desc_ptr) 42621fab1d0595eacf781705ec3509012a28f298245James Bottomley ses_process_descriptor(ecomp, 42721fab1d0595eacf781705ec3509012a28f298245James Bottomley addl_desc_ptr); 42821fab1d0595eacf781705ec3509012a28f298245James Bottomley } 42921fab1d0595eacf781705ec3509012a28f298245James Bottomley if (desc_ptr) 43021fab1d0595eacf781705ec3509012a28f298245James Bottomley desc_ptr += len; 43121fab1d0595eacf781705ec3509012a28f298245James Bottomley 43221fab1d0595eacf781705ec3509012a28f298245James Bottomley if (addl_desc_ptr) 43321fab1d0595eacf781705ec3509012a28f298245James Bottomley addl_desc_ptr += addl_desc_ptr[1] + 2; 43421fab1d0595eacf781705ec3509012a28f298245James Bottomley 43521fab1d0595eacf781705ec3509012a28f298245James Bottomley } 43621fab1d0595eacf781705ec3509012a28f298245James Bottomley } 43721fab1d0595eacf781705ec3509012a28f298245James Bottomley kfree(buf); 43821fab1d0595eacf781705ec3509012a28f298245James Bottomley kfree(hdr_buf); 43921fab1d0595eacf781705ec3509012a28f298245James Bottomley} 44021fab1d0595eacf781705ec3509012a28f298245James Bottomley 4419927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic void ses_match_to_enclosure(struct enclosure_device *edev, 4429927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct scsi_device *sdev) 4439927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 44440c3460f3cad1672f22baadcdbe20b9b3200cc20Matthew Wilcox unsigned char *buf; 4459927c68864e9c39cc317b4f559309ba29e642168James Bottomley unsigned char *desc; 44640c3460f3cad1672f22baadcdbe20b9b3200cc20Matthew Wilcox unsigned int vpd_len; 4479927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct efd efd = { 4489927c68864e9c39cc317b4f559309ba29e642168James Bottomley .addr = 0, 4499927c68864e9c39cc317b4f559309ba29e642168James Bottomley }; 4509927c68864e9c39cc317b4f559309ba29e642168James Bottomley 45140c3460f3cad1672f22baadcdbe20b9b3200cc20Matthew Wilcox buf = scsi_get_vpd_page(sdev, 0x83); 4529927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (!buf) 4539927c68864e9c39cc317b4f559309ba29e642168James Bottomley return; 4549927c68864e9c39cc317b4f559309ba29e642168James Bottomley 45521fab1d0595eacf781705ec3509012a28f298245James Bottomley ses_enclosure_data_process(edev, to_scsi_device(edev->edev.parent), 0); 45621fab1d0595eacf781705ec3509012a28f298245James Bottomley 45740c3460f3cad1672f22baadcdbe20b9b3200cc20Matthew Wilcox vpd_len = ((buf[2] << 8) | buf[3]) + 4; 458671a99c8eb2f1dde08ac5538d8cd912047c61ddfJames Bottomley 4599927c68864e9c39cc317b4f559309ba29e642168James Bottomley desc = buf + 4; 460671a99c8eb2f1dde08ac5538d8cd912047c61ddfJames Bottomley while (desc < buf + vpd_len) { 4619927c68864e9c39cc317b4f559309ba29e642168James Bottomley enum scsi_protocol proto = desc[0] >> 4; 4629927c68864e9c39cc317b4f559309ba29e642168James Bottomley u8 code_set = desc[0] & 0x0f; 4639927c68864e9c39cc317b4f559309ba29e642168James Bottomley u8 piv = desc[1] & 0x80; 4649927c68864e9c39cc317b4f559309ba29e642168James Bottomley u8 assoc = (desc[1] & 0x30) >> 4; 4659927c68864e9c39cc317b4f559309ba29e642168James Bottomley u8 type = desc[1] & 0x0f; 4669927c68864e9c39cc317b4f559309ba29e642168James Bottomley u8 len = desc[3]; 4679927c68864e9c39cc317b4f559309ba29e642168James Bottomley 468b3f1f9aa082b2ab86dec4db3d8b1566af345387eRoel Kluin if (piv && code_set == 1 && assoc == 1 4699927c68864e9c39cc317b4f559309ba29e642168James Bottomley && proto == SCSI_PROTOCOL_SAS && type == 3 && len == 8) 4709927c68864e9c39cc317b4f559309ba29e642168James Bottomley efd.addr = (u64)desc[4] << 56 | 4719927c68864e9c39cc317b4f559309ba29e642168James Bottomley (u64)desc[5] << 48 | 4729927c68864e9c39cc317b4f559309ba29e642168James Bottomley (u64)desc[6] << 40 | 4739927c68864e9c39cc317b4f559309ba29e642168James Bottomley (u64)desc[7] << 32 | 4749927c68864e9c39cc317b4f559309ba29e642168James Bottomley (u64)desc[8] << 24 | 4759927c68864e9c39cc317b4f559309ba29e642168James Bottomley (u64)desc[9] << 16 | 4769927c68864e9c39cc317b4f559309ba29e642168James Bottomley (u64)desc[10] << 8 | 4779927c68864e9c39cc317b4f559309ba29e642168James Bottomley (u64)desc[11]; 4789927c68864e9c39cc317b4f559309ba29e642168James Bottomley 4799927c68864e9c39cc317b4f559309ba29e642168James Bottomley desc += len + 4; 4809927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 4819927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (!efd.addr) 4829927c68864e9c39cc317b4f559309ba29e642168James Bottomley goto free; 4839927c68864e9c39cc317b4f559309ba29e642168James Bottomley 4849927c68864e9c39cc317b4f559309ba29e642168James Bottomley efd.dev = &sdev->sdev_gendev; 4859927c68864e9c39cc317b4f559309ba29e642168James Bottomley 4869927c68864e9c39cc317b4f559309ba29e642168James Bottomley enclosure_for_each_device(ses_enclosure_find_by_addr, &efd); 4879927c68864e9c39cc317b4f559309ba29e642168James Bottomley free: 4889927c68864e9c39cc317b4f559309ba29e642168James Bottomley kfree(buf); 4899927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 4909927c68864e9c39cc317b4f559309ba29e642168James Bottomley 491ee959b00c335d7780136c5abda37809191fe52c3Tony Jonesstatic int ses_intf_add(struct device *cdev, 4929927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct class_interface *intf) 4939927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 494ee959b00c335d7780136c5abda37809191fe52c3Tony Jones struct scsi_device *sdev = to_scsi_device(cdev->parent); 4959927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct scsi_device *tmp_sdev; 49621fab1d0595eacf781705ec3509012a28f298245James Bottomley unsigned char *buf = NULL, *hdr_buf, *type_ptr; 4979927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct ses_device *ses_dev; 4989927c68864e9c39cc317b4f559309ba29e642168James Bottomley u32 result; 49921fab1d0595eacf781705ec3509012a28f298245James Bottomley int i, types, len, components = 0; 5009927c68864e9c39cc317b4f559309ba29e642168James Bottomley int err = -ENOMEM; 5019927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct enclosure_device *edev; 5027c46c20aef185c3782d28c5111dcf1df88bbab32Yinghai Lu struct ses_component *scomp = NULL; 5039927c68864e9c39cc317b4f559309ba29e642168James Bottomley 5049927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (!scsi_device_enclosure(sdev)) { 5059927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* not an enclosure, but might be in one */ 506163f52b6cf3a639df6a72c7937e0eb88b20f1ef3James Bottomley struct enclosure_device *prev = NULL; 507163f52b6cf3a639df6a72c7937e0eb88b20f1ef3James Bottomley 508163f52b6cf3a639df6a72c7937e0eb88b20f1ef3James Bottomley while ((edev = enclosure_find(&sdev->host->shost_gendev, prev)) != NULL) { 5099927c68864e9c39cc317b4f559309ba29e642168James Bottomley ses_match_to_enclosure(edev, sdev); 510163f52b6cf3a639df6a72c7937e0eb88b20f1ef3James Bottomley prev = edev; 5119927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 5129927c68864e9c39cc317b4f559309ba29e642168James Bottomley return -ENODEV; 5139927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 5149927c68864e9c39cc317b4f559309ba29e642168James Bottomley 5159927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* TYPE_ENCLOSURE prints a message in probe */ 5169927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (sdev->type != TYPE_ENCLOSURE) 5179927c68864e9c39cc317b4f559309ba29e642168James Bottomley sdev_printk(KERN_NOTICE, sdev, "Embedded Enclosure Device\n"); 5189927c68864e9c39cc317b4f559309ba29e642168James Bottomley 5199927c68864e9c39cc317b4f559309ba29e642168James Bottomley ses_dev = kzalloc(sizeof(*ses_dev), GFP_KERNEL); 5209927c68864e9c39cc317b4f559309ba29e642168James Bottomley hdr_buf = kzalloc(INIT_ALLOC_SIZE, GFP_KERNEL); 5219927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (!hdr_buf || !ses_dev) 5229927c68864e9c39cc317b4f559309ba29e642168James Bottomley goto err_init_free; 5239927c68864e9c39cc317b4f559309ba29e642168James Bottomley 5249927c68864e9c39cc317b4f559309ba29e642168James Bottomley result = ses_recv_diag(sdev, 1, hdr_buf, INIT_ALLOC_SIZE); 5259927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (result) 5269927c68864e9c39cc317b4f559309ba29e642168James Bottomley goto recv_failed; 5279927c68864e9c39cc317b4f559309ba29e642168James Bottomley 5289927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (hdr_buf[1] != 0) { 5299927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* FIXME: need subenclosure support; I've just never 5309927c68864e9c39cc317b4f559309ba29e642168James Bottomley * seen a device with subenclosures and it makes the 5319927c68864e9c39cc317b4f559309ba29e642168James Bottomley * traversal routines more complex */ 5329927c68864e9c39cc317b4f559309ba29e642168James Bottomley sdev_printk(KERN_ERR, sdev, 5339927c68864e9c39cc317b4f559309ba29e642168James Bottomley "FIXME driver has no support for subenclosures (%d)\n", 534691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu hdr_buf[1]); 5359927c68864e9c39cc317b4f559309ba29e642168James Bottomley goto err_free; 5369927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 5379927c68864e9c39cc317b4f559309ba29e642168James Bottomley 5389927c68864e9c39cc317b4f559309ba29e642168James Bottomley len = (hdr_buf[2] << 8) + hdr_buf[3] + 4; 5399927c68864e9c39cc317b4f559309ba29e642168James Bottomley buf = kzalloc(len, GFP_KERNEL); 5409927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (!buf) 5419927c68864e9c39cc317b4f559309ba29e642168James Bottomley goto err_free; 5429927c68864e9c39cc317b4f559309ba29e642168James Bottomley 5439927c68864e9c39cc317b4f559309ba29e642168James Bottomley result = ses_recv_diag(sdev, 1, buf, len); 5449927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (result) 5459927c68864e9c39cc317b4f559309ba29e642168James Bottomley goto recv_failed; 5469927c68864e9c39cc317b4f559309ba29e642168James Bottomley 5479927c68864e9c39cc317b4f559309ba29e642168James Bottomley types = buf[10]; 5489927c68864e9c39cc317b4f559309ba29e642168James Bottomley 549691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu type_ptr = buf + 12 + buf[11]; 5509927c68864e9c39cc317b4f559309ba29e642168James Bottomley 5519927c68864e9c39cc317b4f559309ba29e642168James Bottomley for (i = 0; i < types; i++, type_ptr += 4) { 5529927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (type_ptr[0] == ENCLOSURE_COMPONENT_DEVICE || 5539927c68864e9c39cc317b4f559309ba29e642168James Bottomley type_ptr[0] == ENCLOSURE_COMPONENT_ARRAY_DEVICE) 5549927c68864e9c39cc317b4f559309ba29e642168James Bottomley components += type_ptr[1]; 5559927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 5567c46c20aef185c3782d28c5111dcf1df88bbab32Yinghai Lu ses_dev->page1 = buf; 5577c46c20aef185c3782d28c5111dcf1df88bbab32Yinghai Lu ses_dev->page1_len = len; 5587c46c20aef185c3782d28c5111dcf1df88bbab32Yinghai Lu buf = NULL; 5599927c68864e9c39cc317b4f559309ba29e642168James Bottomley 5609927c68864e9c39cc317b4f559309ba29e642168James Bottomley result = ses_recv_diag(sdev, 2, hdr_buf, INIT_ALLOC_SIZE); 5619927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (result) 5629927c68864e9c39cc317b4f559309ba29e642168James Bottomley goto recv_failed; 5639927c68864e9c39cc317b4f559309ba29e642168James Bottomley 5649927c68864e9c39cc317b4f559309ba29e642168James Bottomley len = (hdr_buf[2] << 8) + hdr_buf[3] + 4; 5659927c68864e9c39cc317b4f559309ba29e642168James Bottomley buf = kzalloc(len, GFP_KERNEL); 5669927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (!buf) 5679927c68864e9c39cc317b4f559309ba29e642168James Bottomley goto err_free; 5689927c68864e9c39cc317b4f559309ba29e642168James Bottomley 5699927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* make sure getting page 2 actually works */ 5709927c68864e9c39cc317b4f559309ba29e642168James Bottomley result = ses_recv_diag(sdev, 2, buf, len); 5719927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (result) 5729927c68864e9c39cc317b4f559309ba29e642168James Bottomley goto recv_failed; 5739927c68864e9c39cc317b4f559309ba29e642168James Bottomley ses_dev->page2 = buf; 5749927c68864e9c39cc317b4f559309ba29e642168James Bottomley ses_dev->page2_len = len; 5757c46c20aef185c3782d28c5111dcf1df88bbab32Yinghai Lu buf = NULL; 5769927c68864e9c39cc317b4f559309ba29e642168James Bottomley 5779927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* The additional information page --- allows us 5789927c68864e9c39cc317b4f559309ba29e642168James Bottomley * to match up the devices */ 5799927c68864e9c39cc317b4f559309ba29e642168James Bottomley result = ses_recv_diag(sdev, 10, hdr_buf, INIT_ALLOC_SIZE); 580691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu if (!result) { 581691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu 582691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu len = (hdr_buf[2] << 8) + hdr_buf[3] + 4; 583691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu buf = kzalloc(len, GFP_KERNEL); 584691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu if (!buf) 585691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu goto err_free; 586691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu 587691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu result = ses_recv_diag(sdev, 10, buf, len); 588691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu if (result) 589691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu goto recv_failed; 590691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu ses_dev->page10 = buf; 591691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu ses_dev->page10_len = len; 592691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu buf = NULL; 593691b4773aa556d0975dbc25c93e6c8b839dad325Yinghai Lu } 59421fab1d0595eacf781705ec3509012a28f298245James Bottomley kfree(hdr_buf); 5959927c68864e9c39cc317b4f559309ba29e642168James Bottomley 5967c46c20aef185c3782d28c5111dcf1df88bbab32Yinghai Lu scomp = kzalloc(sizeof(struct ses_component) * components, GFP_KERNEL); 5979927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (!scomp) 5987c46c20aef185c3782d28c5111dcf1df88bbab32Yinghai Lu goto err_free; 5999927c68864e9c39cc317b4f559309ba29e642168James Bottomley 60071610f55fa4db63dbf5385929a47c9fb2451f332Kay Sievers edev = enclosure_register(cdev->parent, dev_name(&sdev->sdev_gendev), 6019927c68864e9c39cc317b4f559309ba29e642168James Bottomley components, &ses_enclosure_callbacks); 6029927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (IS_ERR(edev)) { 6039927c68864e9c39cc317b4f559309ba29e642168James Bottomley err = PTR_ERR(edev); 6049927c68864e9c39cc317b4f559309ba29e642168James Bottomley goto err_free; 6059927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 6069927c68864e9c39cc317b4f559309ba29e642168James Bottomley 6079927c68864e9c39cc317b4f559309ba29e642168James Bottomley edev->scratch = ses_dev; 6089927c68864e9c39cc317b4f559309ba29e642168James Bottomley for (i = 0; i < components; i++) 6097c46c20aef185c3782d28c5111dcf1df88bbab32Yinghai Lu edev->component[i].scratch = scomp + i; 6109927c68864e9c39cc317b4f559309ba29e642168James Bottomley 61121fab1d0595eacf781705ec3509012a28f298245James Bottomley ses_enclosure_data_process(edev, sdev, 1); 6129927c68864e9c39cc317b4f559309ba29e642168James Bottomley 6139927c68864e9c39cc317b4f559309ba29e642168James Bottomley /* see if there are any devices matching before 6149927c68864e9c39cc317b4f559309ba29e642168James Bottomley * we found the enclosure */ 6159927c68864e9c39cc317b4f559309ba29e642168James Bottomley shost_for_each_device(tmp_sdev, sdev->host) { 6169927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (tmp_sdev->lun != 0 || scsi_device_enclosure(tmp_sdev)) 6179927c68864e9c39cc317b4f559309ba29e642168James Bottomley continue; 6189927c68864e9c39cc317b4f559309ba29e642168James Bottomley ses_match_to_enclosure(edev, tmp_sdev); 6199927c68864e9c39cc317b4f559309ba29e642168James Bottomley } 6209927c68864e9c39cc317b4f559309ba29e642168James Bottomley 6219927c68864e9c39cc317b4f559309ba29e642168James Bottomley return 0; 6229927c68864e9c39cc317b4f559309ba29e642168James Bottomley 6239927c68864e9c39cc317b4f559309ba29e642168James Bottomley recv_failed: 6249927c68864e9c39cc317b4f559309ba29e642168James Bottomley sdev_printk(KERN_ERR, sdev, "Failed to get diagnostic page 0x%x\n", 6259927c68864e9c39cc317b4f559309ba29e642168James Bottomley result); 6269927c68864e9c39cc317b4f559309ba29e642168James Bottomley err = -ENODEV; 6279927c68864e9c39cc317b4f559309ba29e642168James Bottomley err_free: 6289927c68864e9c39cc317b4f559309ba29e642168James Bottomley kfree(buf); 6297c46c20aef185c3782d28c5111dcf1df88bbab32Yinghai Lu kfree(scomp); 6309927c68864e9c39cc317b4f559309ba29e642168James Bottomley kfree(ses_dev->page10); 6319927c68864e9c39cc317b4f559309ba29e642168James Bottomley kfree(ses_dev->page2); 6329927c68864e9c39cc317b4f559309ba29e642168James Bottomley kfree(ses_dev->page1); 6339927c68864e9c39cc317b4f559309ba29e642168James Bottomley err_init_free: 6349927c68864e9c39cc317b4f559309ba29e642168James Bottomley kfree(ses_dev); 6359927c68864e9c39cc317b4f559309ba29e642168James Bottomley kfree(hdr_buf); 6369927c68864e9c39cc317b4f559309ba29e642168James Bottomley sdev_printk(KERN_ERR, sdev, "Failed to bind enclosure %d\n", err); 6379927c68864e9c39cc317b4f559309ba29e642168James Bottomley return err; 6389927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 6399927c68864e9c39cc317b4f559309ba29e642168James Bottomley 6409927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic int ses_remove(struct device *dev) 6419927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 6429927c68864e9c39cc317b4f559309ba29e642168James Bottomley return 0; 6439927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 6449927c68864e9c39cc317b4f559309ba29e642168James Bottomley 64543d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomleystatic void ses_intf_remove_component(struct scsi_device *sdev) 64643d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley{ 64743d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley struct enclosure_device *edev, *prev = NULL; 64843d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley 64943d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley while ((edev = enclosure_find(&sdev->host->shost_gendev, prev)) != NULL) { 65043d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley prev = edev; 65143d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley if (!enclosure_remove_device(edev, &sdev->sdev_gendev)) 65243d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley break; 65343d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley } 65443d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley if (edev) 65543d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley put_device(&edev->edev); 65643d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley} 65743d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley 65843d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomleystatic void ses_intf_remove_enclosure(struct scsi_device *sdev) 6599927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 6609927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct enclosure_device *edev; 6619927c68864e9c39cc317b4f559309ba29e642168James Bottomley struct ses_device *ses_dev; 6629927c68864e9c39cc317b4f559309ba29e642168James Bottomley 663163f52b6cf3a639df6a72c7937e0eb88b20f1ef3James Bottomley /* exact match to this enclosure */ 66443d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley edev = enclosure_find(&sdev->sdev_gendev, NULL); 6659927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (!edev) 6669927c68864e9c39cc317b4f559309ba29e642168James Bottomley return; 6679927c68864e9c39cc317b4f559309ba29e642168James Bottomley 6689927c68864e9c39cc317b4f559309ba29e642168James Bottomley ses_dev = edev->scratch; 6699927c68864e9c39cc317b4f559309ba29e642168James Bottomley edev->scratch = NULL; 6709927c68864e9c39cc317b4f559309ba29e642168James Bottomley 6717c46c20aef185c3782d28c5111dcf1df88bbab32Yinghai Lu kfree(ses_dev->page10); 6729927c68864e9c39cc317b4f559309ba29e642168James Bottomley kfree(ses_dev->page1); 6739927c68864e9c39cc317b4f559309ba29e642168James Bottomley kfree(ses_dev->page2); 6749927c68864e9c39cc317b4f559309ba29e642168James Bottomley kfree(ses_dev); 6759927c68864e9c39cc317b4f559309ba29e642168James Bottomley 6769927c68864e9c39cc317b4f559309ba29e642168James Bottomley kfree(edev->component[0].scratch); 6779927c68864e9c39cc317b4f559309ba29e642168James Bottomley 678ee959b00c335d7780136c5abda37809191fe52c3Tony Jones put_device(&edev->edev); 6799927c68864e9c39cc317b4f559309ba29e642168James Bottomley enclosure_unregister(edev); 6809927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 6819927c68864e9c39cc317b4f559309ba29e642168James Bottomley 68243d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomleystatic void ses_intf_remove(struct device *cdev, 68343d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley struct class_interface *intf) 68443d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley{ 68543d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley struct scsi_device *sdev = to_scsi_device(cdev->parent); 68643d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley 68743d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley if (!scsi_device_enclosure(sdev)) 68843d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley ses_intf_remove_component(sdev); 68943d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley else 69043d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley ses_intf_remove_enclosure(sdev); 69143d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley} 69243d8eb9cfd0aea93be32181c64e18191b69c211cJames Bottomley 6939927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic struct class_interface ses_interface = { 694ee959b00c335d7780136c5abda37809191fe52c3Tony Jones .add_dev = ses_intf_add, 695ee959b00c335d7780136c5abda37809191fe52c3Tony Jones .remove_dev = ses_intf_remove, 6969927c68864e9c39cc317b4f559309ba29e642168James Bottomley}; 6979927c68864e9c39cc317b4f559309ba29e642168James Bottomley 6989927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic struct scsi_driver ses_template = { 6999927c68864e9c39cc317b4f559309ba29e642168James Bottomley .owner = THIS_MODULE, 7009927c68864e9c39cc317b4f559309ba29e642168James Bottomley .gendrv = { 7019927c68864e9c39cc317b4f559309ba29e642168James Bottomley .name = "ses", 7029927c68864e9c39cc317b4f559309ba29e642168James Bottomley .probe = ses_probe, 7039927c68864e9c39cc317b4f559309ba29e642168James Bottomley .remove = ses_remove, 7049927c68864e9c39cc317b4f559309ba29e642168James Bottomley }, 7059927c68864e9c39cc317b4f559309ba29e642168James Bottomley}; 7069927c68864e9c39cc317b4f559309ba29e642168James Bottomley 7079927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic int __init ses_init(void) 7089927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 7099927c68864e9c39cc317b4f559309ba29e642168James Bottomley int err; 7109927c68864e9c39cc317b4f559309ba29e642168James Bottomley 7119927c68864e9c39cc317b4f559309ba29e642168James Bottomley err = scsi_register_interface(&ses_interface); 7129927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (err) 7139927c68864e9c39cc317b4f559309ba29e642168James Bottomley return err; 7149927c68864e9c39cc317b4f559309ba29e642168James Bottomley 7159927c68864e9c39cc317b4f559309ba29e642168James Bottomley err = scsi_register_driver(&ses_template.gendrv); 7169927c68864e9c39cc317b4f559309ba29e642168James Bottomley if (err) 7179927c68864e9c39cc317b4f559309ba29e642168James Bottomley goto out_unreg; 7189927c68864e9c39cc317b4f559309ba29e642168James Bottomley 7199927c68864e9c39cc317b4f559309ba29e642168James Bottomley return 0; 7209927c68864e9c39cc317b4f559309ba29e642168James Bottomley 7219927c68864e9c39cc317b4f559309ba29e642168James Bottomley out_unreg: 7229927c68864e9c39cc317b4f559309ba29e642168James Bottomley scsi_unregister_interface(&ses_interface); 7239927c68864e9c39cc317b4f559309ba29e642168James Bottomley return err; 7249927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 7259927c68864e9c39cc317b4f559309ba29e642168James Bottomley 7269927c68864e9c39cc317b4f559309ba29e642168James Bottomleystatic void __exit ses_exit(void) 7279927c68864e9c39cc317b4f559309ba29e642168James Bottomley{ 7289927c68864e9c39cc317b4f559309ba29e642168James Bottomley scsi_unregister_driver(&ses_template.gendrv); 7299927c68864e9c39cc317b4f559309ba29e642168James Bottomley scsi_unregister_interface(&ses_interface); 7309927c68864e9c39cc317b4f559309ba29e642168James Bottomley} 7319927c68864e9c39cc317b4f559309ba29e642168James Bottomley 7329927c68864e9c39cc317b4f559309ba29e642168James Bottomleymodule_init(ses_init); 7339927c68864e9c39cc317b4f559309ba29e642168James Bottomleymodule_exit(ses_exit); 7349927c68864e9c39cc317b4f559309ba29e642168James Bottomley 7359927c68864e9c39cc317b4f559309ba29e642168James BottomleyMODULE_ALIAS_SCSI_DEVICE(TYPE_ENCLOSURE); 7369927c68864e9c39cc317b4f559309ba29e642168James Bottomley 7379927c68864e9c39cc317b4f559309ba29e642168James BottomleyMODULE_AUTHOR("James Bottomley"); 7389927c68864e9c39cc317b4f559309ba29e642168James BottomleyMODULE_DESCRIPTION("SCSI Enclosure Services (ses) driver"); 7399927c68864e9c39cc317b4f559309ba29e642168James BottomleyMODULE_LICENSE("GPL v2"); 740